summaryrefslogtreecommitdiffstats
path: root/src/test/ssl
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:17:33 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:17:33 +0000
commit5e45211a64149b3c659b90ff2de6fa982a5a93ed (patch)
tree739caf8c461053357daa9f162bef34516c7bf452 /src/test/ssl
parentInitial commit. (diff)
downloadpostgresql-15-5e45211a64149b3c659b90ff2de6fa982a5a93ed.tar.xz
postgresql-15-5e45211a64149b3c659b90ff2de6fa982a5a93ed.zip
Adding upstream version 15.5.upstream/15.5
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/test/ssl')
-rw-r--r--src/test/ssl/.gitignore2
-rw-r--r--src/test/ssl/Makefile35
-rw-r--r--src/test/ssl/README106
-rw-r--r--src/test/ssl/conf/cas.config60
-rw-r--r--src/test/ssl/conf/client-dn.config15
-rw-r--r--src/test/ssl/conf/client-revoked.config13
-rw-r--r--src/test/ssl/conf/client.config12
-rw-r--r--src/test/ssl/conf/client_ca.config16
-rw-r--r--src/test/ssl/conf/client_ext.config16
-rw-r--r--src/test/ssl/conf/root_ca.config14
-rw-r--r--src/test/ssl/conf/server-cn-and-alt-names.config25
-rw-r--r--src/test/ssl/conf/server-cn-and-ip-alt-names.config24
-rw-r--r--src/test/ssl/conf/server-cn-only.config12
-rw-r--r--src/test/ssl/conf/server-ip-alt-names.config19
-rw-r--r--src/test/ssl/conf/server-ip-cn-and-alt-names.config21
-rw-r--r--src/test/ssl/conf/server-ip-cn-and-dns-alt-names.config21
-rw-r--r--src/test/ssl/conf/server-ip-cn-only.config12
-rw-r--r--src/test/ssl/conf/server-ip-in-dnsname.config18
-rw-r--r--src/test/ssl/conf/server-multiple-alt-names.config20
-rw-r--r--src/test/ssl/conf/server-no-names.config13
-rw-r--r--src/test/ssl/conf/server-revoked.config14
-rw-r--r--src/test/ssl/conf/server-rsapss.config14
-rw-r--r--src/test/ssl/conf/server-single-alt-name.config18
-rw-r--r--src/test/ssl/conf/server_ca.config16
-rw-r--r--src/test/ssl/ssl/.gitignore2
-rw-r--r--src/test/ssl/ssl/both-cas-1.crt57
-rw-r--r--src/test/ssl/ssl/both-cas-2.crt57
-rw-r--r--src/test/ssl/ssl/client+client_ca.crt37
-rw-r--r--src/test/ssl/ssl/client-crldir/9bb9e3c3.r011
-rw-r--r--src/test/ssl/ssl/client-der.keybin0 -> 1191 bytes
-rw-r--r--src/test/ssl/ssl/client-dn.crt19
-rw-r--r--src/test/ssl/ssl/client-dn.key27
-rw-r--r--src/test/ssl/ssl/client-encrypted-der.keybin0 -> 1191 bytes
-rw-r--r--src/test/ssl/ssl/client-encrypted-pem.key30
-rw-r--r--src/test/ssl/ssl/client-revoked.crt18
-rw-r--r--src/test/ssl/ssl/client-revoked.key27
-rw-r--r--src/test/ssl/ssl/client.crl11
-rw-r--r--src/test/ssl/ssl/client.crt18
-rw-r--r--src/test/ssl/ssl/client.key27
-rw-r--r--src/test/ssl/ssl/client_ca.crt19
-rw-r--r--src/test/ssl/ssl/client_ca.key27
-rw-r--r--src/test/ssl/ssl/client_ext.crt21
-rw-r--r--src/test/ssl/ssl/client_ext.key28
-rw-r--r--src/test/ssl/ssl/root+client-crldir/9bb9e3c3.r011
-rw-r--r--src/test/ssl/ssl/root+client-crldir/a3d11bff.r011
-rw-r--r--src/test/ssl/ssl/root+client.crl22
-rw-r--r--src/test/ssl/ssl/root+client_ca.crt38
-rw-r--r--src/test/ssl/ssl/root+server-crldir/a3d11bff.r011
-rw-r--r--src/test/ssl/ssl/root+server-crldir/a836cc2d.r011
-rw-r--r--src/test/ssl/ssl/root+server.crl22
-rw-r--r--src/test/ssl/ssl/root+server_ca.crt38
-rw-r--r--src/test/ssl/ssl/root.crl11
-rw-r--r--src/test/ssl/ssl/root_ca.crt19
-rw-r--r--src/test/ssl/ssl/root_ca.key27
-rw-r--r--src/test/ssl/ssl/server-cn-and-alt-names.crt20
-rw-r--r--src/test/ssl/ssl/server-cn-and-alt-names.key27
-rw-r--r--src/test/ssl/ssl/server-cn-and-ip-alt-names.crt20
-rw-r--r--src/test/ssl/ssl/server-cn-and-ip-alt-names.key27
-rw-r--r--src/test/ssl/ssl/server-cn-only.crt19
-rw-r--r--src/test/ssl/ssl/server-cn-only.key27
-rw-r--r--src/test/ssl/ssl/server-crldir/a836cc2d.r011
-rw-r--r--src/test/ssl/ssl/server-ip-alt-names.crt19
-rw-r--r--src/test/ssl/ssl/server-ip-alt-names.key27
-rw-r--r--src/test/ssl/ssl/server-ip-cn-and-alt-names.crt19
-rw-r--r--src/test/ssl/ssl/server-ip-cn-and-alt-names.key27
-rw-r--r--src/test/ssl/ssl/server-ip-cn-and-dns-alt-names.crt20
-rw-r--r--src/test/ssl/ssl/server-ip-cn-and-dns-alt-names.key27
-rw-r--r--src/test/ssl/ssl/server-ip-cn-only.crt18
-rw-r--r--src/test/ssl/ssl/server-ip-cn-only.key27
-rw-r--r--src/test/ssl/ssl/server-ip-in-dnsname.crt18
-rw-r--r--src/test/ssl/ssl/server-ip-in-dnsname.key27
-rw-r--r--src/test/ssl/ssl/server-multiple-alt-names.crt20
-rw-r--r--src/test/ssl/ssl/server-multiple-alt-names.key27
-rw-r--r--src/test/ssl/ssl/server-no-names.crt18
-rw-r--r--src/test/ssl/ssl/server-no-names.key27
-rw-r--r--src/test/ssl/ssl/server-password.key30
-rw-r--r--src/test/ssl/ssl/server-revoked.crt19
-rw-r--r--src/test/ssl/ssl/server-revoked.key27
-rw-r--r--src/test/ssl/ssl/server-rsapss.crt21
-rw-r--r--src/test/ssl/ssl/server-rsapss.key28
-rw-r--r--src/test/ssl/ssl/server-single-alt-name.crt19
-rw-r--r--src/test/ssl/ssl/server-single-alt-name.key27
-rw-r--r--src/test/ssl/ssl/server.crl11
-rw-r--r--src/test/ssl/ssl/server_ca.crt19
-rw-r--r--src/test/ssl/ssl/server_ca.key27
-rw-r--r--src/test/ssl/sslfiles.mk268
-rw-r--r--src/test/ssl/t/001_ssltests.pl748
-rw-r--r--src/test/ssl/t/002_scram.pl152
-rw-r--r--src/test/ssl/t/003_sslinfo.pl165
-rw-r--r--src/test/ssl/t/SSL/Backend/OpenSSL.pm229
-rw-r--r--src/test/ssl/t/SSL/Server.pm356
91 files changed, 3811 insertions, 0 deletions
diff --git a/src/test/ssl/.gitignore b/src/test/ssl/.gitignore
new file mode 100644
index 0000000..e07b677
--- /dev/null
+++ b/src/test/ssl/.gitignore
@@ -0,0 +1,2 @@
+# Generated by regression tests
+/tmp_check/
diff --git a/src/test/ssl/Makefile b/src/test/ssl/Makefile
new file mode 100644
index 0000000..12b02eb
--- /dev/null
+++ b/src/test/ssl/Makefile
@@ -0,0 +1,35 @@
+#-------------------------------------------------------------------------
+#
+# Makefile for src/test/ssl
+#
+# Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
+# Portions Copyright (c) 1994, Regents of the University of California
+#
+# src/test/ssl/Makefile
+#
+#-------------------------------------------------------------------------
+
+EXTRA_INSTALL = contrib/sslinfo
+
+subdir = src/test/ssl
+top_builddir = ../../..
+include $(top_builddir)/src/Makefile.global
+
+export with_ssl
+
+# The sslfiles targets are separated into their own file due to interactions
+# with settings in Makefile.global.
+.PHONY: sslfiles sslfiles-clean
+sslfiles sslfiles-clean:
+ $(MAKE) -f $(srcdir)/sslfiles.mk $@
+
+clean distclean maintainer-clean:
+ rm -rf tmp_check
+ $(MAKE) -f $(srcdir)/sslfiles.mk $@
+
+# Doesn't depend on sslfiles because we don't rebuild them by default
+check:
+ $(prove_check)
+
+installcheck:
+ $(prove_installcheck)
diff --git a/src/test/ssl/README b/src/test/ssl/README
new file mode 100644
index 0000000..ff55697
--- /dev/null
+++ b/src/test/ssl/README
@@ -0,0 +1,106 @@
+src/test/ssl/README
+
+SSL regression tests
+====================
+
+This directory contains a test suite for SSL support. It tests both
+client-side functionality, i.e. verifying server certificates, and
+server-side functionality, i.e. certificate authorization.
+
+CAUTION: The test server run by this test is configured to listen for
+TCP connections on localhost. Any user on the same host is able to
+log in to the test server while the tests are running. Do not run this
+suite on a multi-user system where you don't trust all local users!
+
+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
+or
+ make installcheck
+You can use "make installcheck" if you previously did "make install".
+In that case, the code in the installation tree is tested. With
+"make check", a temporary installation tree is built from the current
+sources and then tested.
+
+Either way, this test initializes, starts, and stops a test Postgres
+cluster that is accessible to other local users!
+
+See src/test/perl/README for more info about running these tests.
+
+Certificates
+============
+
+The test suite needs a set of public/private key pairs and certificates to
+run:
+
+root_ca
+ root CA, use to sign the server and client CA certificates.
+
+server_ca
+ CA used to sign server certificates.
+
+client_ca
+ CA used to sign client certificates.
+
+server-cn-only
+server-cn-and-alt-names
+server-single-alt-name
+server-multiple-alt-names
+server-no-names
+ server certificates, with small variations in the hostnames present
+ in the certificate. Signed by server_ca.
+
+server-password
+ same as server-cn-only, but password-protected.
+
+client
+ a client certificate, for user "ssltestuser". Signed by client_ca.
+
+client-revoked
+ like "client", but marked as revoked in the client CA's CRL.
+
+In addition, there are a few files that combine various certificates together
+in the same file:
+
+both-cas-1
+ Contains root_ca.crt, client_ca.crt and server_ca.crt, in that order.
+
+both-cas-2
+ Contains root_ca.crt, server_ca.crt and client_ca.crt, in that order.
+
+root+server_ca
+ Contains root_crt and server_ca.crt. For use as client's "sslrootcert"
+ option.
+
+root+client_ca
+ Contains root_crt and client_ca.crt. For use as server's "ssl_ca_file".
+
+client+client_ca
+ Contains client.crt and client_ca.crt in that order. For use as client's
+ certificate chain.
+
+There are also CRLs for each of the CAs: root.crl, server.crl and client.crl.
+
+For convenience, all of these keypairs and certificates are included in the
+ssl/ subdirectory. The Makefile also contains a rule, "make sslfiles", to
+recreate them if you need to make changes. "make sslfiles-clean" is required
+in order to recreate the full set of keypairs and certificates. To rebuild
+separate files, touch (or remove) the files in question and run "make sslfiles".
+This step requires at least OpenSSL 1.1.1.
+
+TODO
+====
+
+* Allow the client-side of the tests to be run on different host easily.
+ Currently, you have to manually set up the certificates for the right
+ hostname, and modify the test file to skip setting up the server. And you
+ have to modify the server to accept connections from the client host.
+
+* Test having multiple server certificates, so that the private key chooses
+ the certificate to present to clients. (And the same in the client-side.)
diff --git a/src/test/ssl/conf/cas.config b/src/test/ssl/conf/cas.config
new file mode 100644
index 0000000..2c48510
--- /dev/null
+++ b/src/test/ssl/conf/cas.config
@@ -0,0 +1,60 @@
+# This file contains the configuration for all the CAs.
+
+# Root CA, used to sign the certificates of the intermediary server and
+# client CAs.
+[ root_ca ]
+dir = ./ssl/
+database = ./ssl/root_ca-certindex
+serial = ./ssl/root_ca.srl
+default_md = sha256
+default_days= 10000
+default_crl_days= 10000
+certificate = ./ssl/root_ca.crt
+private_key = ./ssl/root_ca.key
+new_certs_dir = ./ssl/new_certs_dir
+policy = policy_match
+email_in_dn = no
+copy_extensions = copy
+
+# CA used to sign all the server certificates.
+[ server_ca ]
+dir = ./ssl/
+database = ./ssl/server_ca-certindex
+default_md = sha256
+default_days= 10000
+default_crl_days= 10000
+certificate = ./ssl/server_ca.crt
+private_key = ./ssl/server_ca.key
+new_certs_dir = ./ssl/new_certs_dir
+serial = ./ssl/server_ca.srl
+policy = policy_match
+email_in_dn = no
+copy_extensions = copy
+unique_subject = no
+crl = ./ssl/server.crl
+
+# CA used to sign all the client certificates.
+[ client_ca ]
+dir = ./ssl/
+database = ./ssl/client_ca-certindex
+default_md = sha256
+default_days= 10000
+default_crl_days= 10000
+certificate = ./ssl/client_ca.crt
+private_key = ./ssl/client_ca.key
+new_certs_dir = ./ssl/new_certs_dir
+serial = ./ssl/client_ca.srl
+policy = policy_match
+email_in_dn = no
+copy_extensions = copy
+unique_subject = no
+crl = ./ssl/client.crl
+
+# This is common for all CAs.
+[ policy_match ]
+countryName = optional
+stateOrProvinceName = optional
+organizationName = optional
+organizationalUnitName = optional
+commonName = optional
+emailAddress = optional
diff --git a/src/test/ssl/conf/client-dn.config b/src/test/ssl/conf/client-dn.config
new file mode 100644
index 0000000..0c71d83
--- /dev/null
+++ b/src/test/ssl/conf/client-dn.config
@@ -0,0 +1,15 @@
+# An OpenSSL format CSR config file for creating a client certificate.
+#
+# The certificate is for user "ssltestuser-dn" with a multi-part DN
+
+[ req ]
+distinguished_name = req_distinguished_name
+prompt = no
+
+[ req_distinguished_name ]
+O = PGDG
+0.OU = Engineering
+1.OU = Testing
+CN = ssltestuser-dn
+
+# no extensions in client certs
diff --git a/src/test/ssl/conf/client-revoked.config b/src/test/ssl/conf/client-revoked.config
new file mode 100644
index 0000000..3b82b57
--- /dev/null
+++ b/src/test/ssl/conf/client-revoked.config
@@ -0,0 +1,13 @@
+# An OpenSSL format CSR config file for creating a client certificate.
+#
+# This is identical to the client.config certificate, but this one is revoked
+# later.
+
+[ req ]
+distinguished_name = req_distinguished_name
+prompt = no
+
+[ req_distinguished_name ]
+CN = ssltestuser
+
+# no extensions in client certs
diff --git a/src/test/ssl/conf/client.config b/src/test/ssl/conf/client.config
new file mode 100644
index 0000000..26fc257
--- /dev/null
+++ b/src/test/ssl/conf/client.config
@@ -0,0 +1,12 @@
+# An OpenSSL format CSR config file for creating a client certificate.
+#
+# The certificate is for user "ssltestuser".
+
+[ req ]
+distinguished_name = req_distinguished_name
+prompt = no
+
+[ req_distinguished_name ]
+CN = ssltestuser
+
+# no extensions in client certs
diff --git a/src/test/ssl/conf/client_ca.config b/src/test/ssl/conf/client_ca.config
new file mode 100644
index 0000000..5990f06
--- /dev/null
+++ b/src/test/ssl/conf/client_ca.config
@@ -0,0 +1,16 @@
+# An OpenSSL format CSR config file for creating the client root certificate.
+# This configuration file is also used when operating the CA.
+#
+# This certificate is used to sign client certificates. It is self-signed.
+
+[ req ]
+distinguished_name = req_distinguished_name
+prompt = no
+req_extensions = v3_ca
+
+[ req_distinguished_name ]
+CN = Test CA for PostgreSQL SSL regression test client certs
+
+# Extensions for CA certs
+[ v3_ca ]
+basicConstraints = CA:true
diff --git a/src/test/ssl/conf/client_ext.config b/src/test/ssl/conf/client_ext.config
new file mode 100644
index 0000000..c2dbfef
--- /dev/null
+++ b/src/test/ssl/conf/client_ext.config
@@ -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/conf/root_ca.config b/src/test/ssl/conf/root_ca.config
new file mode 100644
index 0000000..e193186
--- /dev/null
+++ b/src/test/ssl/conf/root_ca.config
@@ -0,0 +1,14 @@
+# A root certificate authority. The server and client CA's certificates
+# are signed by this root CA.
+
+[ req ]
+distinguished_name = req_distinguished_name
+prompt = no
+x509_extensions = v3_ca
+
+[ req_distinguished_name ]
+CN = Test root CA for PostgreSQL SSL regression test suite
+
+# Extensions for CA certs
+[ v3_ca ]
+basicConstraints = CA:true
diff --git a/src/test/ssl/conf/server-cn-and-alt-names.config b/src/test/ssl/conf/server-cn-and-alt-names.config
new file mode 100644
index 0000000..6734251
--- /dev/null
+++ b/src/test/ssl/conf/server-cn-and-alt-names.config
@@ -0,0 +1,25 @@
+# An OpenSSL format CSR config file for creating a server certificate.
+#
+# This certificate contains both a CN, and SANs.
+
+
+[ req ]
+distinguished_name = req_distinguished_name
+req_extensions = v3_req
+prompt = no
+
+[ req_distinguished_name ]
+# Note: According to RFC 2818 and 6125, the CN is ignored, when SANs are
+# present. In practice, the hostname that's put in the CN field is always
+# also listed as a SAN, but we intentionally don't do that here so that we
+# can test adherence to those RFCs.
+CN = common-name.pg-ssltest.test
+OU = PostgreSQL test suite
+
+# For Subject Alternative Names
+[ v3_req ]
+subjectAltName = @alt_names
+
+[ alt_names ]
+DNS.1 = dns1.alt-name.pg-ssltest.test
+DNS.2 = dns2.alt-name.pg-ssltest.test
diff --git a/src/test/ssl/conf/server-cn-and-ip-alt-names.config b/src/test/ssl/conf/server-cn-and-ip-alt-names.config
new file mode 100644
index 0000000..a6fa09b
--- /dev/null
+++ b/src/test/ssl/conf/server-cn-and-ip-alt-names.config
@@ -0,0 +1,24 @@
+# An OpenSSL format CSR config file for creating a server certificate.
+#
+# This certificate contains a CN and SANs for both IPv4 and IPv6.
+
+
+[ req ]
+distinguished_name = req_distinguished_name
+req_extensions = v3_req
+prompt = no
+
+[ req_distinguished_name ]
+# Note: According to RFC 2818 and 6125, the CN is ignored, when DNS names are
+# present in the SANs. But they are silent on whether the CN is checked when IP
+# addresses are present.
+CN = common-name.pg-ssltest.test
+OU = PostgreSQL test suite
+
+# For Subject Alternative Names
+[ v3_req ]
+subjectAltName = @alt_names
+
+[ alt_names ]
+IP.1 = 192.0.2.1
+IP.2 = 2001:DB8::1
diff --git a/src/test/ssl/conf/server-cn-only.config b/src/test/ssl/conf/server-cn-only.config
new file mode 100644
index 0000000..9edb7b7
--- /dev/null
+++ b/src/test/ssl/conf/server-cn-only.config
@@ -0,0 +1,12 @@
+# An OpenSSL format CSR config file for creating a server certificate.
+#
+
+[ req ]
+distinguished_name = req_distinguished_name
+prompt = no
+
+[ req_distinguished_name ]
+CN = common-name.pg-ssltest.test
+OU = PostgreSQL test suite
+
+# No Subject Alternative Names
diff --git a/src/test/ssl/conf/server-ip-alt-names.config b/src/test/ssl/conf/server-ip-alt-names.config
new file mode 100644
index 0000000..c22f229
--- /dev/null
+++ b/src/test/ssl/conf/server-ip-alt-names.config
@@ -0,0 +1,19 @@
+# An OpenSSL format CSR config file for creating a server certificate.
+#
+# This certificate has a two IP-address SANs, and no CN.
+
+[ req ]
+distinguished_name = req_distinguished_name
+req_extensions = v3_req
+prompt = no
+
+[ req_distinguished_name ]
+OU = PostgreSQL test suite
+
+# For Subject Alternative Names
+[ v3_req ]
+subjectAltName = @alt_names
+
+[ alt_names ]
+IP.1 = 192.0.2.1
+IP.2 = 2001:DB8::1
diff --git a/src/test/ssl/conf/server-ip-cn-and-alt-names.config b/src/test/ssl/conf/server-ip-cn-and-alt-names.config
new file mode 100644
index 0000000..a4087f0
--- /dev/null
+++ b/src/test/ssl/conf/server-ip-cn-and-alt-names.config
@@ -0,0 +1,21 @@
+# An OpenSSL format CSR config file for creating a server certificate.
+#
+# This certificate contains both a CN and SANs in IP address format.
+
+
+[ req ]
+distinguished_name = req_distinguished_name
+req_extensions = v3_req
+prompt = no
+
+[ req_distinguished_name ]
+CN = 192.0.2.1
+OU = PostgreSQL test suite
+
+# For Subject Alternative Names
+[ v3_req ]
+subjectAltName = @alt_names
+
+[ alt_names ]
+IP.1 = 192.0.2.2
+IP.2 = 2001:DB8::1
diff --git a/src/test/ssl/conf/server-ip-cn-and-dns-alt-names.config b/src/test/ssl/conf/server-ip-cn-and-dns-alt-names.config
new file mode 100644
index 0000000..7121803
--- /dev/null
+++ b/src/test/ssl/conf/server-ip-cn-and-dns-alt-names.config
@@ -0,0 +1,21 @@
+# An OpenSSL format CSR config file for creating a server certificate.
+#
+# This certificate contains both a CN and SANs in IP address format.
+
+
+[ req ]
+distinguished_name = req_distinguished_name
+req_extensions = v3_req
+prompt = no
+
+[ req_distinguished_name ]
+CN = 192.0.2.1
+OU = PostgreSQL test suite
+
+# For Subject Alternative Names
+[ v3_req ]
+subjectAltName = @alt_names
+
+[ alt_names ]
+DNS.1 = dns1.alt-name.pg-ssltest.test
+DNS.2 = dns2.alt-name.pg-ssltest.test
diff --git a/src/test/ssl/conf/server-ip-cn-only.config b/src/test/ssl/conf/server-ip-cn-only.config
new file mode 100644
index 0000000..585d8bd
--- /dev/null
+++ b/src/test/ssl/conf/server-ip-cn-only.config
@@ -0,0 +1,12 @@
+# An OpenSSL format CSR config file for creating a server certificate.
+#
+
+[ req ]
+distinguished_name = req_distinguished_name
+prompt = no
+
+[ req_distinguished_name ]
+CN = 192.0.2.1
+OU = PostgreSQL test suite
+
+# No Subject Alternative Names
diff --git a/src/test/ssl/conf/server-ip-in-dnsname.config b/src/test/ssl/conf/server-ip-in-dnsname.config
new file mode 100644
index 0000000..b15649a
--- /dev/null
+++ b/src/test/ssl/conf/server-ip-in-dnsname.config
@@ -0,0 +1,18 @@
+# An OpenSSL format CSR config file for creating a server certificate.
+#
+
+[ req ]
+distinguished_name = req_distinguished_name
+req_extensions = v3_req
+prompt = no
+
+[ req_distinguished_name ]
+OU = PostgreSQL test suite
+
+# For Subject Alternative Names
+[ v3_req ]
+subjectAltName = @alt_names
+
+# Normally IP addresses should not go into a dNSName.
+[ alt_names ]
+DNS.1 = 192.0.2.1
diff --git a/src/test/ssl/conf/server-multiple-alt-names.config b/src/test/ssl/conf/server-multiple-alt-names.config
new file mode 100644
index 0000000..fe230df
--- /dev/null
+++ b/src/test/ssl/conf/server-multiple-alt-names.config
@@ -0,0 +1,20 @@
+# An OpenSSL format CSR config file for creating a server certificate.
+#
+# This certificate contains multiple SANs, and no CN.
+
+[ req ]
+distinguished_name = req_distinguished_name
+req_extensions = v3_req
+prompt = no
+
+[ req_distinguished_name ]
+OU = PostgreSQL test suite
+
+# For Subject Alternative Names
+[ v3_req ]
+subjectAltName = @alt_names
+
+[ alt_names ]
+DNS.1 = dns1.alt-name.pg-ssltest.test
+DNS.2 = dns2.alt-name.pg-ssltest.test
+DNS.3 = *.wildcard.pg-ssltest.test
diff --git a/src/test/ssl/conf/server-no-names.config b/src/test/ssl/conf/server-no-names.config
new file mode 100644
index 0000000..89075de
--- /dev/null
+++ b/src/test/ssl/conf/server-no-names.config
@@ -0,0 +1,13 @@
+# An OpenSSL format CSR config file for creating a server certificate.
+#
+# This certificate contains no CN, nor SANs. Not very useful, but make
+# sure the client can handle it gracefully.
+
+[ req ]
+distinguished_name = req_distinguished_name
+prompt = no
+
+[ req_distinguished_name ]
+OU = PostgreSQL test suite
+
+# No Subject Alternative Names
diff --git a/src/test/ssl/conf/server-revoked.config b/src/test/ssl/conf/server-revoked.config
new file mode 100644
index 0000000..c9e1f5d
--- /dev/null
+++ b/src/test/ssl/conf/server-revoked.config
@@ -0,0 +1,14 @@
+# An OpenSSL format CSR config file for creating a server certificate.
+#
+# This is identical to server-cn-only certificate, but this one is revoked
+# later.
+
+[ req ]
+distinguished_name = req_distinguished_name
+prompt = no
+
+[ req_distinguished_name ]
+CN = common-name.pg-ssltest.test
+OU = PostgreSQL test suite
+
+# No Subject Alternative Names
diff --git a/src/test/ssl/conf/server-rsapss.config b/src/test/ssl/conf/server-rsapss.config
new file mode 100644
index 0000000..391f9b8
--- /dev/null
+++ b/src/test/ssl/conf/server-rsapss.config
@@ -0,0 +1,14 @@
+# An OpenSSL format CSR config file for creating a server certificate.
+#
+# This is identical to server-cn-only certificate, but we specify
+# RSA-PSS as the algorithm on the command line.
+
+[ req ]
+distinguished_name = req_distinguished_name
+prompt = no
+
+[ req_distinguished_name ]
+CN = common-name.pg-ssltest.test
+OU = PostgreSQL test suite
+
+# No Subject Alternative Names \ No newline at end of file
diff --git a/src/test/ssl/conf/server-single-alt-name.config b/src/test/ssl/conf/server-single-alt-name.config
new file mode 100644
index 0000000..2b3ddf4
--- /dev/null
+++ b/src/test/ssl/conf/server-single-alt-name.config
@@ -0,0 +1,18 @@
+# An OpenSSL format CSR config file for creating a server certificate.
+#
+# This certificate has a single SAN, and no CN.
+
+[ req ]
+distinguished_name = req_distinguished_name
+req_extensions = v3_req
+prompt = no
+
+[ req_distinguished_name ]
+OU = PostgreSQL test suite
+
+# For Subject Alternative Names
+[ v3_req ]
+subjectAltName = @alt_names
+
+[ alt_names ]
+DNS.1 = single.alt-name.pg-ssltest.test
diff --git a/src/test/ssl/conf/server_ca.config b/src/test/ssl/conf/server_ca.config
new file mode 100644
index 0000000..496aaba
--- /dev/null
+++ b/src/test/ssl/conf/server_ca.config
@@ -0,0 +1,16 @@
+# An OpenSSL format CSR config file for creating the server root certificate.
+# This configuration file is also used when operating the CA.
+#
+# This certificate is used to sign server certificates. It is self-signed.
+
+[ req ]
+distinguished_name = req_distinguished_name
+prompt = no
+req_extensions = v3_ca
+
+[ req_distinguished_name ]
+CN = Test CA for PostgreSQL SSL regression test server certs
+
+# Extensions for CA certs
+[ v3_ca ]
+basicConstraints = CA:true
diff --git a/src/test/ssl/ssl/.gitignore b/src/test/ssl/ssl/.gitignore
new file mode 100644
index 0000000..9d5fd27
--- /dev/null
+++ b/src/test/ssl/ssl/.gitignore
@@ -0,0 +1,2 @@
+/*.old
+/new_certs_dir/
diff --git a/src/test/ssl/ssl/both-cas-1.crt b/src/test/ssl/ssl/both-cas-1.crt
new file mode 100644
index 0000000..4f4bc70
--- /dev/null
+++ b/src/test/ssl/ssl/both-cas-1.crt
@@ -0,0 +1,57 @@
+-----BEGIN CERTIFICATE-----
+MIIDHjCCAgagAwIBAgIUF+e8lCA0vD0zKtxIDVPdDY/IkgUwDQYJKoZIhvcNAQEL
+BQAwQDE+MDwGA1UEAww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCBy
+ZWdyZXNzaW9uIHRlc3Qgc3VpdGUwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIx
+MjA3WjBAMT4wPAYDVQQDDDVUZXN0IHJvb3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NM
+IHJlZ3Jlc3Npb24gdGVzdCBzdWl0ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBALZ81vKKBJlxgjwuNoK67I4IE9zfSLb0eHbgZwZxDVzdmFejARrHlWk3
++MK7Nav7RLSJ990am33zb58CTHc7YYVlBp07+PwLXzypqWkhYfok1OYYjyjCrFDs
+sjcJI3hRCZNEz+wYsG+tdYWJ+gRPQOWfh0YfO2rFgXAIMLiF6lyWzf1eOM+OjYrF
+/eyzwbMaJkkGa/AyZKz3wZiPq0jTuYLVmH4MK7MBOsUfSmsBsn/ohyRCQzM+ol0v
+Qlsrulj8usponRPDh9ng4PB5OSgR79YimQZnASQzJxiUvMADrKL5L6KwLxJlzbqY
+R0b5mLh8KBzBQmSh3Aj2e2I7Z17hdaMCAwEAAaMQMA4wDAYDVR0TBAUwAwEB/zAN
+BgkqhkiG9w0BAQsFAAOCAQEAY6h2MurDkE2LAG3TPhTrAczflR3np6y1cDxeRzRi
+br2bczXVfgWDsBZDhKXdIQldYQhAUU7u09GtAtujWnkJguPuVtlhEfuW/eXpcBI2
+XQnrkaTqjD/DDMJGijNVAXEHSecEls6uEuuSCxmm7hVD781Aqo0HlLPDhTEkko6r
+IYFO0QyFG+oFSVhUp2KuarQNHVgopOmWbtbrq2KqaL5Gm5AXPSRzEhIeobYdSnTe
+OCZhKLxVZiZmO71BBwsTgwtU58/G9e2ciGGdltI8ANlmVfdtwgRz3b7H9EUZat6s
+kubl/m5HWBsKJEWEzFWrWkQV3ipoTmorJ6KCGABBCeVYmg==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDFDCCAfygAwIBAgIIICEDAxQSBwEwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
+Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
+c3Qgc3VpdGUwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjBCMUAwPgYD
+VQQDDDdUZXN0IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qg
+Y2xpZW50IGNlcnRzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu+ce
+8rkNfoCvI9Wjug9pxsptsdjhZ4s7ZZ8eD5VlloryK2JccusQIX61XY8I3OZjLTgq
+1SpZbHQvktRH6gmU7tfoBdEnRuXB7idkbYOKIrC0hdttb/5rDzjQGtXTmwoVrCcJ
+nvO1Whay/gdsoqX1tT1MTPWu/6dfQkQXA0PizVvmBasAEQchxqtcH2rSc6TPE13v
+lxJ0X1vSlz92uT6kenrxUDs43AH/kASdIQBHXVA4XWBAm7NRqwKX7BBwbsF2m3Qh
++NY9Bf9MnJHLcnVnwZdlW5nd7H7BTB43XvkiYascqusYki+fY58eGSprZ/VUjmGx
+pgQnQXWCu0U3JyUL/QIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB
+CwUAA4IBAQC1syY2Rk02m5PGtfkMUIU7ZSe0mM+g0BgWAyCF/mFFYdfY0xHtqy0x
+QWkW9OR0KBl4JpphDDolHoNL3TLydH3t4inX8SAOpaUdsjMcIPKqjT1htQm0Pk5r
+vFYvKuVrxMnV0F+wMmZRuziKWrZlVDwBMfCAchzuVexDWfcjTmUQmhZxJuUzORw3
+swgh9HIpxjMkgdlHodbMAEpMIkkoeJnph3I9uTocXZbK/lAInggQdm0Q+on1ZT0A
+ljO/6jisDZzIguE4ZAQ2DfYsGI8H3tz/+76uIwwBNOmu0woUDSWXVcPWiviq49Bi
+GmH0KlUfWAphj86IfTWXT1HRay3eZQt3
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDFDCCAfygAwIBAgIIICEDAxQSBwAwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
+Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
+c3Qgc3VpdGUwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjBCMUAwPgYD
+VQQDDDdUZXN0IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qg
+c2VydmVyIGNlcnRzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4kp2
+GW5nPb6QrSrtbClfZeutyQnHrm4TMPBoNepFdIVxBX/04BguM5ImDRze/huOWA+z
+atJAQqt3R7dsDwnOnPKUKCOuHX6a1aj5L86HtVgaWTXrZFE5NtL9PIzXkWu13UW0
+UesHtbPVRv6a6fB7Npph6hHy7iPZb009A8/lTJnxSPC39u/K/sPqjrVZaAJF+wDs
+qCxCZTUtAUFvWFnR/TeXLWlFzBupS1djgI7PltbJqSn6SKTAgNZTxpRJbu9Icp6J
+/50ELwT++0n0KWVXNHrDNfI5Gaa+SxClAsPsei2jLKpgR6QFC3wn38Z9q9LjAVuC
++FWhoN1uhYeoricEXwIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB
+CwUAA4IBAQCdCA/EoXrustoV4jJGbkdXDuOUkBurwggSNBAqUBSDvCohRoD77Ecb
+QVuzPNxWKG+E4PwfUq2ha+2yPONEJ28ZgsbHq5qlJDMJ43wlcjn6wmmAJNeSpO8F
+0V9d2X/4wNZty9/zbwTnw26KChgDHumQ0WIbCoBtdqy8KDswYOvpgws6dqc021I7
+UrFo6vZek7VoApbJgkDL6qYADa6ApfW43ThH4sViFITeYt/kSHgmy2Udhs34jMM8
+xsFP/uYpRi1b1glenwSIKiHjD4/C9vnWQt5K3gRBvYukEj2Bw9VkNRpBVCi0cOoA
+OuwX3bwzNYNbZQv4K66oRpvuoEjCNeHg
+-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/both-cas-2.crt b/src/test/ssl/ssl/both-cas-2.crt
new file mode 100644
index 0000000..01d0c4d
--- /dev/null
+++ b/src/test/ssl/ssl/both-cas-2.crt
@@ -0,0 +1,57 @@
+-----BEGIN CERTIFICATE-----
+MIIDHjCCAgagAwIBAgIUF+e8lCA0vD0zKtxIDVPdDY/IkgUwDQYJKoZIhvcNAQEL
+BQAwQDE+MDwGA1UEAww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCBy
+ZWdyZXNzaW9uIHRlc3Qgc3VpdGUwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIx
+MjA3WjBAMT4wPAYDVQQDDDVUZXN0IHJvb3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NM
+IHJlZ3Jlc3Npb24gdGVzdCBzdWl0ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBALZ81vKKBJlxgjwuNoK67I4IE9zfSLb0eHbgZwZxDVzdmFejARrHlWk3
++MK7Nav7RLSJ990am33zb58CTHc7YYVlBp07+PwLXzypqWkhYfok1OYYjyjCrFDs
+sjcJI3hRCZNEz+wYsG+tdYWJ+gRPQOWfh0YfO2rFgXAIMLiF6lyWzf1eOM+OjYrF
+/eyzwbMaJkkGa/AyZKz3wZiPq0jTuYLVmH4MK7MBOsUfSmsBsn/ohyRCQzM+ol0v
+Qlsrulj8usponRPDh9ng4PB5OSgR79YimQZnASQzJxiUvMADrKL5L6KwLxJlzbqY
+R0b5mLh8KBzBQmSh3Aj2e2I7Z17hdaMCAwEAAaMQMA4wDAYDVR0TBAUwAwEB/zAN
+BgkqhkiG9w0BAQsFAAOCAQEAY6h2MurDkE2LAG3TPhTrAczflR3np6y1cDxeRzRi
+br2bczXVfgWDsBZDhKXdIQldYQhAUU7u09GtAtujWnkJguPuVtlhEfuW/eXpcBI2
+XQnrkaTqjD/DDMJGijNVAXEHSecEls6uEuuSCxmm7hVD781Aqo0HlLPDhTEkko6r
+IYFO0QyFG+oFSVhUp2KuarQNHVgopOmWbtbrq2KqaL5Gm5AXPSRzEhIeobYdSnTe
+OCZhKLxVZiZmO71BBwsTgwtU58/G9e2ciGGdltI8ANlmVfdtwgRz3b7H9EUZat6s
+kubl/m5HWBsKJEWEzFWrWkQV3ipoTmorJ6KCGABBCeVYmg==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDFDCCAfygAwIBAgIIICEDAxQSBwAwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
+Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
+c3Qgc3VpdGUwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjBCMUAwPgYD
+VQQDDDdUZXN0IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qg
+c2VydmVyIGNlcnRzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4kp2
+GW5nPb6QrSrtbClfZeutyQnHrm4TMPBoNepFdIVxBX/04BguM5ImDRze/huOWA+z
+atJAQqt3R7dsDwnOnPKUKCOuHX6a1aj5L86HtVgaWTXrZFE5NtL9PIzXkWu13UW0
+UesHtbPVRv6a6fB7Npph6hHy7iPZb009A8/lTJnxSPC39u/K/sPqjrVZaAJF+wDs
+qCxCZTUtAUFvWFnR/TeXLWlFzBupS1djgI7PltbJqSn6SKTAgNZTxpRJbu9Icp6J
+/50ELwT++0n0KWVXNHrDNfI5Gaa+SxClAsPsei2jLKpgR6QFC3wn38Z9q9LjAVuC
++FWhoN1uhYeoricEXwIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB
+CwUAA4IBAQCdCA/EoXrustoV4jJGbkdXDuOUkBurwggSNBAqUBSDvCohRoD77Ecb
+QVuzPNxWKG+E4PwfUq2ha+2yPONEJ28ZgsbHq5qlJDMJ43wlcjn6wmmAJNeSpO8F
+0V9d2X/4wNZty9/zbwTnw26KChgDHumQ0WIbCoBtdqy8KDswYOvpgws6dqc021I7
+UrFo6vZek7VoApbJgkDL6qYADa6ApfW43ThH4sViFITeYt/kSHgmy2Udhs34jMM8
+xsFP/uYpRi1b1glenwSIKiHjD4/C9vnWQt5K3gRBvYukEj2Bw9VkNRpBVCi0cOoA
+OuwX3bwzNYNbZQv4K66oRpvuoEjCNeHg
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDFDCCAfygAwIBAgIIICEDAxQSBwEwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
+Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
+c3Qgc3VpdGUwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjBCMUAwPgYD
+VQQDDDdUZXN0IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qg
+Y2xpZW50IGNlcnRzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu+ce
+8rkNfoCvI9Wjug9pxsptsdjhZ4s7ZZ8eD5VlloryK2JccusQIX61XY8I3OZjLTgq
+1SpZbHQvktRH6gmU7tfoBdEnRuXB7idkbYOKIrC0hdttb/5rDzjQGtXTmwoVrCcJ
+nvO1Whay/gdsoqX1tT1MTPWu/6dfQkQXA0PizVvmBasAEQchxqtcH2rSc6TPE13v
+lxJ0X1vSlz92uT6kenrxUDs43AH/kASdIQBHXVA4XWBAm7NRqwKX7BBwbsF2m3Qh
++NY9Bf9MnJHLcnVnwZdlW5nd7H7BTB43XvkiYascqusYki+fY58eGSprZ/VUjmGx
+pgQnQXWCu0U3JyUL/QIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB
+CwUAA4IBAQC1syY2Rk02m5PGtfkMUIU7ZSe0mM+g0BgWAyCF/mFFYdfY0xHtqy0x
+QWkW9OR0KBl4JpphDDolHoNL3TLydH3t4inX8SAOpaUdsjMcIPKqjT1htQm0Pk5r
+vFYvKuVrxMnV0F+wMmZRuziKWrZlVDwBMfCAchzuVexDWfcjTmUQmhZxJuUzORw3
+swgh9HIpxjMkgdlHodbMAEpMIkkoeJnph3I9uTocXZbK/lAInggQdm0Q+on1ZT0A
+ljO/6jisDZzIguE4ZAQ2DfYsGI8H3tz/+76uIwwBNOmu0woUDSWXVcPWiviq49Bi
+GmH0KlUfWAphj86IfTWXT1HRay3eZQt3
+-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/client+client_ca.crt b/src/test/ssl/ssl/client+client_ca.crt
new file mode 100644
index 0000000..7fafa14
--- /dev/null
+++ b/src/test/ssl/ssl/client+client_ca.crt
@@ -0,0 +1,37 @@
+-----BEGIN CERTIFICATE-----
+MIIC0zCCAbsCCCAhAwMUEgcAMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
+c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBjbGllbnQg
+Y2VydHMwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjAWMRQwEgYDVQQD
+DAtzc2x0ZXN0dXNlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALSL
+oC6h8sBABL8kWRjFQJHZNcwmuRRWjzhBYR4gDKcBThCBIuEr5PZEkkXnJniXKHct
+bCzaBarUwG+bWGg6BiFWX3PP5MZvLG7ExP9yTrDjdwjKozkJCNWSow0hdYLaxkpm
+rYI6rDJ5T1CZBRLD4RYOjU39WVIxYkHlhJYtH0Cdv5PuzCOEtLdKQySSVq6heJen
+koLvK7AaF1x8uDiwM+o9t69pORWbOh/6aCCPeYmvhPIRvEqyZjGvPJ2kXau4R1vN
+NmepRIZ0VjQ/rQxo7dGWk38cfgsTeFI4G26DiYn08pFR47swUdfiMyx3MaGQiz9X
+I2nUqjM+W84iUxrR82MCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEACSZo32raJHcB
+rYHeomzynmzgMVBHSA4XsXZVQw4+zBUER+/ZdQbtw6F/qdeWRvTl8TJjwoydta7u
+4gUkgAnQhYm2f8XEBe/+MUegH+y54Yk6rtmkdLxJLGKZ0IUfYkn20sg/NZrltbog
+A8glWRGVD8cEOaxUaNSQ4Xqmqsqjd6Kh8snVfIIcWgKgnTNgyapM5ePBpS2IREhN
+u9fjikQQf6F/dycsm22OP7aWsp1XPs3nqnoq9ZnhQrITMwsGcjbU7+v8La2GbiJV
+8yAy136NSXUujIG/8eqhICWZPqj+KbdVZupOsUeVoeuSwLXJjm4GWY0xH92emqCI
+ac+HriJv5w==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDFDCCAfygAwIBAgIIICEDAxQSBwEwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
+Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
+c3Qgc3VpdGUwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjBCMUAwPgYD
+VQQDDDdUZXN0IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qg
+Y2xpZW50IGNlcnRzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu+ce
+8rkNfoCvI9Wjug9pxsptsdjhZ4s7ZZ8eD5VlloryK2JccusQIX61XY8I3OZjLTgq
+1SpZbHQvktRH6gmU7tfoBdEnRuXB7idkbYOKIrC0hdttb/5rDzjQGtXTmwoVrCcJ
+nvO1Whay/gdsoqX1tT1MTPWu/6dfQkQXA0PizVvmBasAEQchxqtcH2rSc6TPE13v
+lxJ0X1vSlz92uT6kenrxUDs43AH/kASdIQBHXVA4XWBAm7NRqwKX7BBwbsF2m3Qh
++NY9Bf9MnJHLcnVnwZdlW5nd7H7BTB43XvkiYascqusYki+fY58eGSprZ/VUjmGx
+pgQnQXWCu0U3JyUL/QIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB
+CwUAA4IBAQC1syY2Rk02m5PGtfkMUIU7ZSe0mM+g0BgWAyCF/mFFYdfY0xHtqy0x
+QWkW9OR0KBl4JpphDDolHoNL3TLydH3t4inX8SAOpaUdsjMcIPKqjT1htQm0Pk5r
+vFYvKuVrxMnV0F+wMmZRuziKWrZlVDwBMfCAchzuVexDWfcjTmUQmhZxJuUzORw3
+swgh9HIpxjMkgdlHodbMAEpMIkkoeJnph3I9uTocXZbK/lAInggQdm0Q+on1ZT0A
+ljO/6jisDZzIguE4ZAQ2DfYsGI8H3tz/+76uIwwBNOmu0woUDSWXVcPWiviq49Bi
+GmH0KlUfWAphj86IfTWXT1HRay3eZQt3
+-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/client-crldir/9bb9e3c3.r0 b/src/test/ssl/ssl/client-crldir/9bb9e3c3.r0
new file mode 100644
index 0000000..d93791b
--- /dev/null
+++ b/src/test/ssl/ssl/client-crldir/9bb9e3c3.r0
@@ -0,0 +1,11 @@
+-----BEGIN X509 CRL-----
+MIIBpTCBjjANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
+b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3QgY2xpZW50IGNlcnRzFw0yMTAz
+MDMyMjEyMDdaFw00ODA3MTkyMjEyMDdaMBswGQIIICEDAxQSBwEXDTIxMDMwMzIy
+MTIwN1owDQYJKoZIhvcNAQELBQADggEBAC1AJ+HhHg74uXNXdoXLnqDhowdx1y3z
+GKSTPH4iW6jvGp7mMeJhq7cx5kzC+Rqtjui7FjkXbvGd4f6ZVKf30tDD/LvVLxLU
+Up7TmwZjYHbB4NPMyMyqUxtusjYm6HFhbfJwf11TQFwF9yRN3MI4os3J9KTzvhY1
+AvfyEqhBdeygkc1cDduZD+cx7QFYtaeD316q4lz8yfegtxwng8/JDlThu72zdpWV
+w0LuzLei1A9cPXoXfMxRGVEOrDt5z3ArNqdD0bnXTTYqm1IX8ZRHDNeUi4NuFCCu
+tKWT4j9ad4mMcJ6TY/8MiJ14mSJmWSR8115QT69rrQIdDu0sA/sBJX0=
+-----END X509 CRL-----
diff --git a/src/test/ssl/ssl/client-der.key b/src/test/ssl/ssl/client-der.key
new file mode 100644
index 0000000..c9be5f9
--- /dev/null
+++ b/src/test/ssl/ssl/client-der.key
Binary files differ
diff --git a/src/test/ssl/ssl/client-dn.crt b/src/test/ssl/ssl/client-dn.crt
new file mode 100644
index 0000000..0db14e5
--- /dev/null
+++ b/src/test/ssl/ssl/client-dn.crt
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDDTCCAfUCCCAhBikTA0IAMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
+c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBjbGllbnQg
+Y2VydHMwHhcNMjEwNjI5MjAwMzQyWhcNNDgxMTE0MjAwMzQyWjBQMQ0wCwYDVQQK
+DARQR0RHMRQwEgYDVQQLDAtFbmdpbmVlcmluZzEQMA4GA1UECwwHVGVzdGluZzEX
+MBUGA1UEAwwOc3NsdGVzdHVzZXItZG4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQDES64qtkofPjeG4VbUVKfzABLC0CurvxqLTEpokq/St9WAWDrzc8PJ
+YireEZp4ec5rHVyQVvHqzzaZFAMvbRUQgMdGKG4Vgkn8l96KxHa4Q6yxYoQOts10
+AuvU9LuGKT0lxndMggHDmREUOAkFYKp7IeypseUGkJ6sWs+DlTwK1hST+EUAU/5f
+q/pAngJ+oar20m8WNxaAhJUKtBBecdRdqYy/h3Ab43iPhj+N9IFXiSV9EWhteBae
+L/TEE+s7/4L74xwvJe2EiVETo3lMy2aVJ4/4pOMq7U+Gr/0wxk0jqRrOahAE6pOI
+cQFBFsOkyUaC4dzqtjeSrsw5igQbJC19AgMBAAEwDQYJKoZIhvcNAQELBQADggEB
+AECbQQ9rBzCexNI3VKDVA+CZa0ib48XbcJwXmva3spvjjCB5cGPToyF1B+4mVg1H
+1uM/XRAoQmNRtB+xKEAceMSxJA02tBlwMOclXlO0oGLYyc+S61K+UEPSk6Kka4aC
+NpeLSqN5ahC9z8C5uMJl36pFf13aU05uRkXKcI4gkn02I4jRc/a8gF7URdhdf920
+KmYSUh1V0B3pPAB6ArqJ60iHOqkCYIIIbi2EpVP53IKkoB9tr4ud8oMoN6ggIXU1
+2oHvnaKJ7RZaQNefS3WweyHxr4cCVtEour/ELph48OuW6Y5jqPT+5Ln3Qz0e6KW9
+o3thBx0aKSYlmt9gH254M9M=
+-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/client-dn.key b/src/test/ssl/ssl/client-dn.key
new file mode 100644
index 0000000..1d67ef0
--- /dev/null
+++ b/src/test/ssl/ssl/client-dn.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAxEuuKrZKHz43huFW1FSn8wASwtArq78ai0xKaJKv0rfVgFg6
+83PDyWIq3hGaeHnOax1ckFbx6s82mRQDL20VEIDHRihuFYJJ/JfeisR2uEOssWKE
+DrbNdALr1PS7hik9JcZ3TIIBw5kRFDgJBWCqeyHsqbHlBpCerFrPg5U8CtYUk/hF
+AFP+X6v6QJ4CfqGq9tJvFjcWgISVCrQQXnHUXamMv4dwG+N4j4Y/jfSBV4klfRFo
+bXgWni/0xBPrO/+C++McLyXthIlRE6N5TMtmlSeP+KTjKu1Phq/9MMZNI6kazmoQ
+BOqTiHEBQRbDpMlGguHc6rY3kq7MOYoEGyQtfQIDAQABAoIBABqL3Zb7JhUJlfrQ
+uKxocnojdWYRPwawBof2Hk38IHkP0XjU9cv8yOqQMxnrKYfHeUn1I5KFn5vQwCJ9
+mVytlN6xe8GaMCEKiLT3WOpNXXzX8h/fIdrXj/tzda9MFZw0MYfNSk73egOYzL1+
+QoIOq5+RW+8rFr0Hi93lPhEeeotAYWDQgx9Ye/NSW6vK2m47hdBKf9SBsWs+Vafa
+mC9Bf4LQqRYSJZee1zDwIh+Om7/JTsjMZYU0/lpycRz7V5uHbamXKlOXF54ow3Wn
+CJ9eVVWo7sb3CaeJ0p2sHIFp89ybMQ2vvmNr6aJNtZWd5WYxsjKs40rVq6DiUlFn
+T6CK7uECgYEA/Ks4/OnZnorhaHwYTs0LqiPSM7oZw4qchCNDMoE3WngsaZoWUKmr
+2JTY6uYP/B+oWgwPBdDiPRDeGqtVNZSAVsZEDMbiqZxwHaLi9OKJ7sKgK8Q6ANV1
+q5qgH1yXXygWhlol/Nf9bbnGWWoN+33zvnADeKRcT/1gZLEQpJ46DHUCgYEAxuIx
+k/EOOT9kyC5WrBDY3l7veb/WGRQgXTXiCJaO4d7IYh8UpUXlg0ZYF4RfeKRsSd07
+n9QdW6ImrtDloNyG6HnDknYsPRUs8JcuuyrxaOsZ/p9LS76ItNV7gzREf4N/7jrD
+c6TJappgXm+dgXg6ENuyk05hzjT6qdvm9V80m+kCgYEA7kfXRYSP61lT/AJTtjTf
+FEQV3xxZYbRdqKvMmluLxTDhyXE8LDPm0SiGbPgsCPwd+1W18SktwqMeoo4DnLUA
+V1VBJb+GUKgsf3Z2jLT7mYRIIx46CUFFaGE5MnpScrXOkEOB4bIb2RfCu94tc4gz
+jtv6GhL+z5zHBA6MAIMLgWUCgYAlynNLPkHKpP4cf5mehnD/CCEPDGG9UDK6I3P4
+18r8pl2DL463vOlYoXQ5u8B8ZxngizY6L48Ii244R59qipzj7cc4vFW5oZ1xdfi+
+PfGzUwEUfeZL1T+axPn8O2FMrYsQlH/xKH3RUNZA+4p9QIAgFe7/yKQTD8QVpKBl
+PZr8iQKBgBjdrgMt1Az98ECXJCjM4uui2S9UenNQVmhmxgZUpHqfNk+WEvIIthDi
+FEJPSTHyhTI9XIrhhwNkW3UZMjMndAiNylXGfJdr/xGwLM57t5HhGgljSboV7Mnw
+RFnh2FZxa3i/8g+4lAPZNwU0W/JU46wgg4C2Eu/Ne7jA8XUXYu9t
+-----END RSA PRIVATE KEY-----
diff --git a/src/test/ssl/ssl/client-encrypted-der.key b/src/test/ssl/ssl/client-encrypted-der.key
new file mode 100644
index 0000000..c9be5f9
--- /dev/null
+++ b/src/test/ssl/ssl/client-encrypted-der.key
Binary files differ
diff --git a/src/test/ssl/ssl/client-encrypted-pem.key b/src/test/ssl/ssl/client-encrypted-pem.key
new file mode 100644
index 0000000..1e7052a
--- /dev/null
+++ b/src/test/ssl/ssl/client-encrypted-pem.key
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-CBC,E619306A930B60F360BF805500BA5659
+
+B9aYmIdIoF7hT9tJARMQWE7Ii7g+KDNaF4U0ljBsxgbtMyi9DQrlrFsbUO0Wy6iO
+UY/h57UA1pk7yF+rwkTK0L2t0j/d+HZc3ddsN3cZ040PmX8+8QZJWRUs2ywTLa4O
+JxPm2rUxLSeVa+FY9Nr1Cl6meQ2JS7MA7KBNuriBWNleGGgkbBMaH7zq98aOJmaz
+l02J2wrJ5STP2UI8uEaT/UtAgLInlAljCSg5oe5cj4u9UyUkRN7fj4mexq1r5YNU
+zTu7GrgcAdXrhsAhg9mAJol4frwsQuEiJbVIurAAvCrJk7Gm8xVjKCN1stDOASAY
+aawO1huIdTzjbGXFHBtJ4YuRClXZr5ij6kN+KeQaS+JLjehsAb6762l9wUPP5Bxv
+8c6CCxc+U4ndN0ZQPsx0UrJ/AYO1s12mebuKZvIdNoYdLIqJLfX/HSrzaXw6XA8b
+gAvVOruKGq12v71OrIdahxSzRs7s6GODGynSayFprn3CK+GZJumwQ0EK+fBzrzB1
+8JTp98qwMYfSuDmGl8VbT9k8OZFZbDD4k5wj8fHx5R4zkdgfNqBNAKXPrwm5uRT8
++0mnYdP3ZnihnZnAoZvGXOE77TcZ/N9fLvwkBpwPmtftbn10HwlwXQgmn1ijMj60
+ZOYo1fvKJMmvCr+NUtyJALIvUdLQmjWx0PoZetIb24KBkTkr2ciU1d1RDEwOfffZ
+jwTfcJU/AXnxPBR6MBT9a+YkaMiOU0JF7vs/x0hG/o8GsXQJB/G7Vzakg0hxQ1WF
+KU0jInXPf2uCiBMEwuWRPHh25wspLjsHgt5pD55vE/M9Q7LFOez/9/RQqmmjDjZH
+sLJtdAjN57aaIhtzbYIYa7K7Eu5v0NrZ5++wP3h82aTy9PIlSmRGY8WiZSDDir0P
+w+PBP7JN/3ifqXURUmSDGbfdArbyuuF79Say6N9ijFeBAZrCgauw3jBs1dhusGJ/
+T6wh8mjdGf8SRm9SQdGuIyK7M657z3P0WRlpHN4beeGpzgGVexqjiyvtwQNH8kps
+3EDNwTe3HJMWf7G2FNjqtM0h3fnaB7d+prfzZIL5Y1Somgfiljp7zG/FfkYEybK6
+8OvW6O8byCSqJzugUa5HCv//iPYFrcALAXtva4KXtfauGhKmWpn3Wa5AW9/034H6
+QW/A8mcKSMKhGixZj5MZKGTMA9cRus3IRTAYnhCd5njJ1N/o67wwTGVuXVu6ExrM
+wY/WjkRrDlRopqo0U3wodHjfZ8/837rINwmcqzXTxasu+ApWUVZFuuQh/q3i8aTv
+BzFVOfLylxpIsoQHBQvNdM/u0HGXbw7wyjs6n+LCjeGwRuxKkoYlKf5cItNLDNvF
+6LYwA44BJ3/XfUSVZRD8PAVp5haUgpesPym1G5QdvYN4rWE6lsAtGSZDatWvaCsI
+S0qTwLFbw9BvclwkvJicvLwAmKiGMDyAwGNCPLnG7nZ48to4dXD93LmgC/mnENbp
+7EgW7fUtMvz0Lt2Xcd26ZTlJdOkT3sdKPSDxhgqsQoI4dQSmB4Fz40HsFvFtTCuF
+FXMFXjSkjiKrdfI+CQ1tJGXKpYAod8PcZ89vN3TjxehwhK6GxS0CiOJ+phh6q22i
+-----END RSA PRIVATE KEY-----
diff --git a/src/test/ssl/ssl/client-revoked.crt b/src/test/ssl/ssl/client-revoked.crt
new file mode 100644
index 0000000..51ebe92
--- /dev/null
+++ b/src/test/ssl/ssl/client-revoked.crt
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC0zCCAbsCCCAhAwMUEgcBMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
+c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBjbGllbnQg
+Y2VydHMwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjAWMRQwEgYDVQQD
+DAtzc2x0ZXN0dXNlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKAX
+JmNmfqmvpVAeWEmJxi7feku2sZKA7yMyyZMCboBqsNVO9gOpQFE8gD1Z7bJm4aDK
+QxByuspYPFOBwty9YW4UqRa4kyEyd08x+PsHQx9SmWJTNpNIH6yq5LCcme37QMrg
+b8wUZRWwXsaKUfVUI6oALjSgcibMJXTntCsD9J5m/07U/ZZALe1460rreTFHsxVZ
+708Wm5u7UHIgxvvEKhNG/JR9zd1Tl1mVgnlz0a8G6Dt22gJnLnuFdtDdACwET/kG
+TRJQWuyavpe+1TY53kZNO442hOzwhlZVnz4IKaWaLNQMtbG9iYStEvaWa8p0E/3J
+N6oRuELiqXJp/wW3v/MCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAcVhPcu55HcSf
+Mci38T/fOBaiDUvzWwG/XlQRzFxcS+ZY/vYMbgor6PliGlCFBF4Mca2qtTs7zXRz
+8aLNVX53p98Cnnn97mW4aYNbNdM87R76IqJdj40brEolu1JNOyFJRYzoaebABf9r
+R64FTt3YVM9qjJrHG/apYwKwgAMxVzZ/M+3ujahP/8mOYD/Utj+lYHnXJmuHAYE6
+EnTxTSb2J+IsK8KuPoGjUPNZRW8zIUE0luMpJahvtmFVW91Vue7dW0AOmHpjmGUB
+J9Vwxe7KJRW5/4dz6kMD2pKY3D9sBgXeku/QDVz/hdyB5YT0WChFiZn20DZyhOtu
+moHgw8OJzg==
+-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/client-revoked.key b/src/test/ssl/ssl/client-revoked.key
new file mode 100644
index 0000000..a915c6f
--- /dev/null
+++ b/src/test/ssl/ssl/client-revoked.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpQIBAAKCAQEAoBcmY2Z+qa+lUB5YSYnGLt96S7axkoDvIzLJkwJugGqw1U72
+A6lAUTyAPVntsmbhoMpDEHK6ylg8U4HC3L1hbhSpFriTITJ3TzH4+wdDH1KZYlM2
+k0gfrKrksJyZ7ftAyuBvzBRlFbBexopR9VQjqgAuNKByJswldOe0KwP0nmb/TtT9
+lkAt7XjrSut5MUezFVnvTxabm7tQciDG+8QqE0b8lH3N3VOXWZWCeXPRrwboO3ba
+Amcue4V20N0ALARP+QZNElBa7Jq+l77VNjneRk07jjaE7PCGVlWfPggppZos1Ay1
+sb2JhK0S9pZrynQT/ck3qhG4QuKpcmn/Bbe/8wIDAQABAoIBAQCVmUx8MrlGZCa9
+Gb4y6hZSku87dXu2hdnyMHGBeRI92nVov6LRhQXfZAQKUND4l39cu+WzpyK6F344
+ItgvYqF7Nr9TxiNnMDuhu/cIzZ6B1LQU1+H1+73toryV9aE6bEH904FlWeGkRO4r
+5fH0qS2ynPyQnSZO7xJJjoQkdkvPAMId7ovA5kKRLqRbXORGkbHhDdzoBB5ogRmV
+CInIfO7mI85OJXXtggPNb7L9Tmb39/i+D/pagIWehzb9WOSnMnJ6//ORkEntqEOl
+yaalJVF7uhiQbMcqA+ZJN9WwQPeLOeYowGD48cCsdjCgOhxM0EVWhtkDoC5MeZSz
+0XQ7vrwxAoGBANFVznbReMP914AtDDY3ISrtsU3AZVuTpfi19+jogTOHZakt0ntt
+Ztaymh0CBcE1DSbSdPLLtVpyhkvfmZRRIzv48xV2LHRibVkx5hncXQRrm+85B2vh
+PMJ1/CO5Rky6DOq6RXWEbHKv56ZPUKeaokJsusUgafKkM8DpWDz5Re6VAoGBAMPH
+FBRrTIL6N8vv4IRmCBk8axmAtbAKOcSghSLtGi8oX4wgL0nltoW28aE4uNiLb7Dh
+vDOqluhc6ejaI6tCSo1+f1JSsiCvieFfRR76I0AQCGtdKZTu7hfxT+GQURm09iYX
+T06VqIfpTOgQ6O6ArYSF+nF1DxrzUJdVpywxqzpnAoGBANAiWaMHyORN2lul7pNl
+IwQ0yuo8lkqENixgePpJWlTqlWitl66C6xIjCFo5LZGZdtcXv5G8ezdP0TlVO7Ud
+K0Qw1TiMg8zAJGrf0yH5WT7Q43zqHffkPe43Mxgt2bjl73ve8rrSjKVHQrK3/8B1
+XklfJCBlhxHqs05mdAZD7oU1AoGAeD6BurjcWWXNd1hxkWAJgVZ2gUdoUCM3r+jX
+XMg72NL3PF1YLg8Et8PRTLBF99pMU1uR+DnCTh0jHX09gyZIG/ehw7I+7YxjJyUY
+kxoXJHW0dhzWOT82xUXVRjkZVqyqsmKGt0F8LV3BepdIOZSW/lo7pAu9p1PiH9Df
+yGkJPekCgYEAneTtCsznABsSw/5E2kq3fWQWZ+N9IIHQCNor4YnEWLiTe7Btexqv
++joMPnKWCZ9DqzgltmcNN4r/2nkNdJ9KJwlwkp6bKl9AnDSdSWuXUsxB8pecGylo
+cD4WMBUQqd2IEI8678Pr9fOHA97YzTF87HfBGcsW/g25dzfOfb8A0YE=
+-----END RSA PRIVATE KEY-----
diff --git a/src/test/ssl/ssl/client.crl b/src/test/ssl/ssl/client.crl
new file mode 100644
index 0000000..d93791b
--- /dev/null
+++ b/src/test/ssl/ssl/client.crl
@@ -0,0 +1,11 @@
+-----BEGIN X509 CRL-----
+MIIBpTCBjjANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
+b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3QgY2xpZW50IGNlcnRzFw0yMTAz
+MDMyMjEyMDdaFw00ODA3MTkyMjEyMDdaMBswGQIIICEDAxQSBwEXDTIxMDMwMzIy
+MTIwN1owDQYJKoZIhvcNAQELBQADggEBAC1AJ+HhHg74uXNXdoXLnqDhowdx1y3z
+GKSTPH4iW6jvGp7mMeJhq7cx5kzC+Rqtjui7FjkXbvGd4f6ZVKf30tDD/LvVLxLU
+Up7TmwZjYHbB4NPMyMyqUxtusjYm6HFhbfJwf11TQFwF9yRN3MI4os3J9KTzvhY1
+AvfyEqhBdeygkc1cDduZD+cx7QFYtaeD316q4lz8yfegtxwng8/JDlThu72zdpWV
+w0LuzLei1A9cPXoXfMxRGVEOrDt5z3ArNqdD0bnXTTYqm1IX8ZRHDNeUi4NuFCCu
+tKWT4j9ad4mMcJ6TY/8MiJ14mSJmWSR8115QT69rrQIdDu0sA/sBJX0=
+-----END X509 CRL-----
diff --git a/src/test/ssl/ssl/client.crt b/src/test/ssl/ssl/client.crt
new file mode 100644
index 0000000..1f6ae05
--- /dev/null
+++ b/src/test/ssl/ssl/client.crt
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC0zCCAbsCCCAhAwMUEgcAMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
+c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBjbGllbnQg
+Y2VydHMwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjAWMRQwEgYDVQQD
+DAtzc2x0ZXN0dXNlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALSL
+oC6h8sBABL8kWRjFQJHZNcwmuRRWjzhBYR4gDKcBThCBIuEr5PZEkkXnJniXKHct
+bCzaBarUwG+bWGg6BiFWX3PP5MZvLG7ExP9yTrDjdwjKozkJCNWSow0hdYLaxkpm
+rYI6rDJ5T1CZBRLD4RYOjU39WVIxYkHlhJYtH0Cdv5PuzCOEtLdKQySSVq6heJen
+koLvK7AaF1x8uDiwM+o9t69pORWbOh/6aCCPeYmvhPIRvEqyZjGvPJ2kXau4R1vN
+NmepRIZ0VjQ/rQxo7dGWk38cfgsTeFI4G26DiYn08pFR47swUdfiMyx3MaGQiz9X
+I2nUqjM+W84iUxrR82MCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEACSZo32raJHcB
+rYHeomzynmzgMVBHSA4XsXZVQw4+zBUER+/ZdQbtw6F/qdeWRvTl8TJjwoydta7u
+4gUkgAnQhYm2f8XEBe/+MUegH+y54Yk6rtmkdLxJLGKZ0IUfYkn20sg/NZrltbog
+A8glWRGVD8cEOaxUaNSQ4Xqmqsqjd6Kh8snVfIIcWgKgnTNgyapM5ePBpS2IREhN
+u9fjikQQf6F/dycsm22OP7aWsp1XPs3nqnoq9ZnhQrITMwsGcjbU7+v8La2GbiJV
+8yAy136NSXUujIG/8eqhICWZPqj+KbdVZupOsUeVoeuSwLXJjm4GWY0xH92emqCI
+ac+HriJv5w==
+-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/client.key b/src/test/ssl/ssl/client.key
new file mode 100644
index 0000000..21e1e9f
--- /dev/null
+++ b/src/test/ssl/ssl/client.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAtIugLqHywEAEvyRZGMVAkdk1zCa5FFaPOEFhHiAMpwFOEIEi
+4Svk9kSSRecmeJcody1sLNoFqtTAb5tYaDoGIVZfc8/kxm8sbsTE/3JOsON3CMqj
+OQkI1ZKjDSF1gtrGSmatgjqsMnlPUJkFEsPhFg6NTf1ZUjFiQeWEli0fQJ2/k+7M
+I4S0t0pDJJJWrqF4l6eSgu8rsBoXXHy4OLAz6j23r2k5FZs6H/poII95ia+E8hG8
+SrJmMa88naRdq7hHW802Z6lEhnRWND+tDGjt0ZaTfxx+CxN4UjgbboOJifTykVHj
+uzBR1+IzLHcxoZCLP1cjadSqMz5bziJTGtHzYwIDAQABAoIBAA7mqzzODvwBDKM9
++8CInzCqbb9AvuvHzSBGfR6AZKrv96JzFg7hkY8lz7DHSCyRxTw42oHFKMyVrKBJ
+gP1xNIpR16T2VppuGIu33855f7cnvu5R0zDk5v7BkIWH6mv3ZIBFgzKJZybvTjWH
+u5x14EDyyITUUSfwfXyU1eGTLc4mU01g4kArSDy7dqWi9xrixfaiTH+bbfmoE96v
+6kiwICZuoYaBLwOi9e7iHenhpF9X+BHNgt+x4dO5FSTtb15G96CnTM1U8xN2rf6y
+pfwkWH0NoeeTvuGvzfFgQMVxk/72VtM21rntGA4z6ig7xHKZLJ2mFSb29/uISZKv
+P1igV5ECgYEA6J2J5vPYLpXGmwthICaPiVSShUfZpZ05w+/p5KmFwtuyENSTtD+0
+nr/TY3mQNqecDTZsN5lillqnlZcAXVFce9A6iyQuIYz1FwO6K+mQLDshl7sXRNrK
+AeThubltaieOtSXbeji8kmmEK95tO//Y7DNjLVn8gZ4Q2hOT97e8hCsCgYEAxrIK
+/RWqU94JuGwJFzUDpgaJYQG5rcc+J0cZejjFl5ppY0+DPMNBKrGaObUrXAPmWBS9
+Gm4qBN3Zd1F8qEnHF+dw5vZY5hcvANcKRqXiPUkdzmpBNtlb/E+bGIEmhlh96gxN
+AKQEPh2UM+Gc4eDfFUgfLnmqTLfPOSzpCXejmakCgYEAyZVMnoKOw8A0PsSbxNrl
+5OMPnsTnTmh0WOKeVPS74GO3anJuFfRnOHOQY1JDsbmKuMCDA6O/FgE13aLgQ/5w
+ITQQp+gQui6Hbwxh2BAuSsZrlCwkPB1GlmGdY+/Xa/kf6MgH7WEhudgLHGFDVI2h
+lP/rYK/s7P7oJ7RztGbbzcUCgYBzZ9wMDXZlyfRZYp6RFSCuYOOQLYFcVvpZs+kv
+XSQfHveRUBCIzVvfYVKTrA+oHTe/9yOy40OSmgyCShkeYeO6lZm0/Ga8FcEeOshk
+KltSf1JJntuL8QmFbfNGc1Ud+O4Bb+2Vrq4sKd/3llYZuBO6d65svwvUDXrV2ajs
+78ldKQKBgAZROsYDYkdwBJmKCipRAwp7qS67zUpGSzjnDdswa0S6ECMcbx46qhcc
+IvFx/2rjLDIZUVjXkt/U9phWIAq/xMd0Euk+zvIdMmiaJeAmT8DzxVyM4iHGWbuY
+qWpoSLJe8d+xDrHkQZHh+Pb4CpJwRNs3c0MGY3+i/PPTjxq4em8p
+-----END RSA PRIVATE KEY-----
diff --git a/src/test/ssl/ssl/client_ca.crt b/src/test/ssl/ssl/client_ca.crt
new file mode 100644
index 0000000..ef48749
--- /dev/null
+++ b/src/test/ssl/ssl/client_ca.crt
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDFDCCAfygAwIBAgIIICEDAxQSBwEwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
+Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
+c3Qgc3VpdGUwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjBCMUAwPgYD
+VQQDDDdUZXN0IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qg
+Y2xpZW50IGNlcnRzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu+ce
+8rkNfoCvI9Wjug9pxsptsdjhZ4s7ZZ8eD5VlloryK2JccusQIX61XY8I3OZjLTgq
+1SpZbHQvktRH6gmU7tfoBdEnRuXB7idkbYOKIrC0hdttb/5rDzjQGtXTmwoVrCcJ
+nvO1Whay/gdsoqX1tT1MTPWu/6dfQkQXA0PizVvmBasAEQchxqtcH2rSc6TPE13v
+lxJ0X1vSlz92uT6kenrxUDs43AH/kASdIQBHXVA4XWBAm7NRqwKX7BBwbsF2m3Qh
++NY9Bf9MnJHLcnVnwZdlW5nd7H7BTB43XvkiYascqusYki+fY58eGSprZ/VUjmGx
+pgQnQXWCu0U3JyUL/QIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB
+CwUAA4IBAQC1syY2Rk02m5PGtfkMUIU7ZSe0mM+g0BgWAyCF/mFFYdfY0xHtqy0x
+QWkW9OR0KBl4JpphDDolHoNL3TLydH3t4inX8SAOpaUdsjMcIPKqjT1htQm0Pk5r
+vFYvKuVrxMnV0F+wMmZRuziKWrZlVDwBMfCAchzuVexDWfcjTmUQmhZxJuUzORw3
+swgh9HIpxjMkgdlHodbMAEpMIkkoeJnph3I9uTocXZbK/lAInggQdm0Q+on1ZT0A
+ljO/6jisDZzIguE4ZAQ2DfYsGI8H3tz/+76uIwwBNOmu0woUDSWXVcPWiviq49Bi
+GmH0KlUfWAphj86IfTWXT1HRay3eZQt3
+-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/client_ca.key b/src/test/ssl/ssl/client_ca.key
new file mode 100644
index 0000000..f79ea97
--- /dev/null
+++ b/src/test/ssl/ssl/client_ca.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpQIBAAKCAQEAu+ce8rkNfoCvI9Wjug9pxsptsdjhZ4s7ZZ8eD5VlloryK2Jc
+cusQIX61XY8I3OZjLTgq1SpZbHQvktRH6gmU7tfoBdEnRuXB7idkbYOKIrC0hdtt
+b/5rDzjQGtXTmwoVrCcJnvO1Whay/gdsoqX1tT1MTPWu/6dfQkQXA0PizVvmBasA
+EQchxqtcH2rSc6TPE13vlxJ0X1vSlz92uT6kenrxUDs43AH/kASdIQBHXVA4XWBA
+m7NRqwKX7BBwbsF2m3Qh+NY9Bf9MnJHLcnVnwZdlW5nd7H7BTB43XvkiYascqusY
+ki+fY58eGSprZ/VUjmGxpgQnQXWCu0U3JyUL/QIDAQABAoIBAD4TfcrsTcP0GWg6
+RSvLucM9zv2JS/YcLlRFO/YkAfq5DoY8qZQhiiO2q44sGd54kl03CBeCNSa6P5k/
+Xj64SaaaV4HMdjBa6TWXd/siELmjLRBnzIDKSW4u87lZ2N2IeF52SxxjIQ+RHjME
+GuSk9UaZ6KIoLFczYSoQOpYOkFgNKdu0RcxGG+fM+AQMtCP/KjL61suBxeoLG+Cs
+kAB7EUsSbX+PsOy3V9l9n62F/NDPQBuNgwAMOF2qOXnMTsDHTkxlkka8CIHZeRLX
+VBifO6bf2TCpAQ9+cH+lmfXtOWYExvZvgGeMB9WE8gXSxOnSD0uqxSLgCAwr8sM1
+6TDitIECgYEA7K/p0efjOaw9/+hAJniXS+RQ90WXTkq3asIR+NDvpig2jIJAQ9Lx
+ngGQ86PlEIL53O7Ol4Av4589pmSAD1Q5dEXsXOcDod0mx0nidAp/C//fhyfX7xR2
+irIWDxKKuCc4xbiVWNGeXXC0cJufY2b6gbgpSfwC/i5CUlGzkLdoGKECgYEAyzwq
+g4jtU0O90wKl6REQuepCMTL6+/E6sFDl7OXxZdmeeTyLLgWevAwHOQeOhGuX9RMO
+ZYPngLSbrSC40o2i9369AUkJa0Meabji4fir7GvYzwarq/xHQjMvpGV13DVKEUoQ
+JLdZ9uJRih2tVeqlCiD1abCu3eVh2+Sc17iWKd0CgYEA13g19p+R3lkNgEDg1aUG
+p1JM2y8BVYbzfz75uXgME0mcj0GsW5JX364xVXwo9mUmLplAfe92qVO4fhgT9OCK
+BW36hYDRb7Oyr851V4qOqk/gIFyHWeFZIV6KcmJA4vDh4C3v2BHMh+gofDNQYN/I
+wfrzq6S+3MMkIWi7fc1Z+MECgYEApv4nCLGIIDS3Ux0H6nwFPF5KSVbUeBP830d5
+xbAjLEcmOgQPcJ9ZkLZpcOjOp+wojk08NRmvLUg56oXKl+edkrNm5hl3TdV2tfQf
+KQJFchwjp+iZQtYmTzTz3qcnsutukspCfYjSuVO5ID3GYaROPAZc4J028kk6oY41
+eePIL1kCgYEA1ghHZmNhhsjxrkfWFME/nSWFazyEx1XmMagmvXw9rlrnBPFdtLsU
+ZfFHM5gVaW/JMql0OGDjMSwc3fEEH8wd1eLXVxfCVLzvk8XVe81ahthMpndii813
+Cspl0AS9jpOkQK8JTZ38YAIqIr7H057veqAY+TbvIAdxoh+7DyW/aBs=
+-----END RSA PRIVATE KEY-----
diff --git a/src/test/ssl/ssl/client_ext.crt b/src/test/ssl/ssl/client_ext.crt
new file mode 100644
index 0000000..9874ce4
--- /dev/null
+++ b/src/test/ssl/ssl/client_ext.crt
@@ -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
index 0000000..04e5930
--- /dev/null
+++ b/src/test/ssl/ssl/client_ext.key
@@ -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-----
diff --git a/src/test/ssl/ssl/root+client-crldir/9bb9e3c3.r0 b/src/test/ssl/ssl/root+client-crldir/9bb9e3c3.r0
new file mode 100644
index 0000000..d93791b
--- /dev/null
+++ b/src/test/ssl/ssl/root+client-crldir/9bb9e3c3.r0
@@ -0,0 +1,11 @@
+-----BEGIN X509 CRL-----
+MIIBpTCBjjANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
+b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3QgY2xpZW50IGNlcnRzFw0yMTAz
+MDMyMjEyMDdaFw00ODA3MTkyMjEyMDdaMBswGQIIICEDAxQSBwEXDTIxMDMwMzIy
+MTIwN1owDQYJKoZIhvcNAQELBQADggEBAC1AJ+HhHg74uXNXdoXLnqDhowdx1y3z
+GKSTPH4iW6jvGp7mMeJhq7cx5kzC+Rqtjui7FjkXbvGd4f6ZVKf30tDD/LvVLxLU
+Up7TmwZjYHbB4NPMyMyqUxtusjYm6HFhbfJwf11TQFwF9yRN3MI4os3J9KTzvhY1
+AvfyEqhBdeygkc1cDduZD+cx7QFYtaeD316q4lz8yfegtxwng8/JDlThu72zdpWV
+w0LuzLei1A9cPXoXfMxRGVEOrDt5z3ArNqdD0bnXTTYqm1IX8ZRHDNeUi4NuFCCu
+tKWT4j9ad4mMcJ6TY/8MiJ14mSJmWSR8115QT69rrQIdDu0sA/sBJX0=
+-----END X509 CRL-----
diff --git a/src/test/ssl/ssl/root+client-crldir/a3d11bff.r0 b/src/test/ssl/ssl/root+client-crldir/a3d11bff.r0
new file mode 100644
index 0000000..5b42d38
--- /dev/null
+++ b/src/test/ssl/ssl/root+client-crldir/a3d11bff.r0
@@ -0,0 +1,11 @@
+-----BEGIN X509 CRL-----
+MIIBhTBvMA0GCSqGSIb3DQEBCwUAMEAxPjA8BgNVBAMMNVRlc3Qgcm9vdCBDQSBm
+b3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHN1aXRlFw0yMTAzMDMy
+MjEyMDdaFw00ODA3MTkyMjEyMDdaMA0GCSqGSIb3DQEBCwUAA4IBAQACkv0Nnerr
+ZkacIUbRaANYLIsYAGfKuBYDAp4I4CCC2hvXL64KLDMZbVfB4vp3hvM2FZdT2AwT
+SBNr2rpYp7Coc3GeCoWPcClgSrABD3Z5GY1YAdLGiXVKaH3CmdJTznhEPagE4z5R
+40qbmw8RU062ZbyFamBO7VTY7IFBA8PxuTgAH/3OYa5Jne8umyPQT5fKnqyRBz/A
+6/b5RCxuPOWFm0MJKrEaAeLk6eaCxUUqXQP+8mHscphqZTOynjAW0NPH+/x2NpxS
+/C5LTeOzJ28k8X434h323G18n/CFERWnhW1UyR1Pt6oSGMZqU5UwbSrwTsf8tSSc
++GrJP3XxJ1OC
+-----END X509 CRL-----
diff --git a/src/test/ssl/ssl/root+client.crl b/src/test/ssl/ssl/root+client.crl
new file mode 100644
index 0000000..02eff4d
--- /dev/null
+++ b/src/test/ssl/ssl/root+client.crl
@@ -0,0 +1,22 @@
+-----BEGIN X509 CRL-----
+MIIBhTBvMA0GCSqGSIb3DQEBCwUAMEAxPjA8BgNVBAMMNVRlc3Qgcm9vdCBDQSBm
+b3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHN1aXRlFw0yMTAzMDMy
+MjEyMDdaFw00ODA3MTkyMjEyMDdaMA0GCSqGSIb3DQEBCwUAA4IBAQACkv0Nnerr
+ZkacIUbRaANYLIsYAGfKuBYDAp4I4CCC2hvXL64KLDMZbVfB4vp3hvM2FZdT2AwT
+SBNr2rpYp7Coc3GeCoWPcClgSrABD3Z5GY1YAdLGiXVKaH3CmdJTznhEPagE4z5R
+40qbmw8RU062ZbyFamBO7VTY7IFBA8PxuTgAH/3OYa5Jne8umyPQT5fKnqyRBz/A
+6/b5RCxuPOWFm0MJKrEaAeLk6eaCxUUqXQP+8mHscphqZTOynjAW0NPH+/x2NpxS
+/C5LTeOzJ28k8X434h323G18n/CFERWnhW1UyR1Pt6oSGMZqU5UwbSrwTsf8tSSc
++GrJP3XxJ1OC
+-----END X509 CRL-----
+-----BEGIN X509 CRL-----
+MIIBpTCBjjANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
+b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3QgY2xpZW50IGNlcnRzFw0yMTAz
+MDMyMjEyMDdaFw00ODA3MTkyMjEyMDdaMBswGQIIICEDAxQSBwEXDTIxMDMwMzIy
+MTIwN1owDQYJKoZIhvcNAQELBQADggEBAC1AJ+HhHg74uXNXdoXLnqDhowdx1y3z
+GKSTPH4iW6jvGp7mMeJhq7cx5kzC+Rqtjui7FjkXbvGd4f6ZVKf30tDD/LvVLxLU
+Up7TmwZjYHbB4NPMyMyqUxtusjYm6HFhbfJwf11TQFwF9yRN3MI4os3J9KTzvhY1
+AvfyEqhBdeygkc1cDduZD+cx7QFYtaeD316q4lz8yfegtxwng8/JDlThu72zdpWV
+w0LuzLei1A9cPXoXfMxRGVEOrDt5z3ArNqdD0bnXTTYqm1IX8ZRHDNeUi4NuFCCu
+tKWT4j9ad4mMcJ6TY/8MiJ14mSJmWSR8115QT69rrQIdDu0sA/sBJX0=
+-----END X509 CRL-----
diff --git a/src/test/ssl/ssl/root+client_ca.crt b/src/test/ssl/ssl/root+client_ca.crt
new file mode 100644
index 0000000..7819c54
--- /dev/null
+++ b/src/test/ssl/ssl/root+client_ca.crt
@@ -0,0 +1,38 @@
+-----BEGIN CERTIFICATE-----
+MIIDHjCCAgagAwIBAgIUF+e8lCA0vD0zKtxIDVPdDY/IkgUwDQYJKoZIhvcNAQEL
+BQAwQDE+MDwGA1UEAww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCBy
+ZWdyZXNzaW9uIHRlc3Qgc3VpdGUwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIx
+MjA3WjBAMT4wPAYDVQQDDDVUZXN0IHJvb3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NM
+IHJlZ3Jlc3Npb24gdGVzdCBzdWl0ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBALZ81vKKBJlxgjwuNoK67I4IE9zfSLb0eHbgZwZxDVzdmFejARrHlWk3
++MK7Nav7RLSJ990am33zb58CTHc7YYVlBp07+PwLXzypqWkhYfok1OYYjyjCrFDs
+sjcJI3hRCZNEz+wYsG+tdYWJ+gRPQOWfh0YfO2rFgXAIMLiF6lyWzf1eOM+OjYrF
+/eyzwbMaJkkGa/AyZKz3wZiPq0jTuYLVmH4MK7MBOsUfSmsBsn/ohyRCQzM+ol0v
+Qlsrulj8usponRPDh9ng4PB5OSgR79YimQZnASQzJxiUvMADrKL5L6KwLxJlzbqY
+R0b5mLh8KBzBQmSh3Aj2e2I7Z17hdaMCAwEAAaMQMA4wDAYDVR0TBAUwAwEB/zAN
+BgkqhkiG9w0BAQsFAAOCAQEAY6h2MurDkE2LAG3TPhTrAczflR3np6y1cDxeRzRi
+br2bczXVfgWDsBZDhKXdIQldYQhAUU7u09GtAtujWnkJguPuVtlhEfuW/eXpcBI2
+XQnrkaTqjD/DDMJGijNVAXEHSecEls6uEuuSCxmm7hVD781Aqo0HlLPDhTEkko6r
+IYFO0QyFG+oFSVhUp2KuarQNHVgopOmWbtbrq2KqaL5Gm5AXPSRzEhIeobYdSnTe
+OCZhKLxVZiZmO71BBwsTgwtU58/G9e2ciGGdltI8ANlmVfdtwgRz3b7H9EUZat6s
+kubl/m5HWBsKJEWEzFWrWkQV3ipoTmorJ6KCGABBCeVYmg==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDFDCCAfygAwIBAgIIICEDAxQSBwEwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
+Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
+c3Qgc3VpdGUwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjBCMUAwPgYD
+VQQDDDdUZXN0IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qg
+Y2xpZW50IGNlcnRzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu+ce
+8rkNfoCvI9Wjug9pxsptsdjhZ4s7ZZ8eD5VlloryK2JccusQIX61XY8I3OZjLTgq
+1SpZbHQvktRH6gmU7tfoBdEnRuXB7idkbYOKIrC0hdttb/5rDzjQGtXTmwoVrCcJ
+nvO1Whay/gdsoqX1tT1MTPWu/6dfQkQXA0PizVvmBasAEQchxqtcH2rSc6TPE13v
+lxJ0X1vSlz92uT6kenrxUDs43AH/kASdIQBHXVA4XWBAm7NRqwKX7BBwbsF2m3Qh
++NY9Bf9MnJHLcnVnwZdlW5nd7H7BTB43XvkiYascqusYki+fY58eGSprZ/VUjmGx
+pgQnQXWCu0U3JyUL/QIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB
+CwUAA4IBAQC1syY2Rk02m5PGtfkMUIU7ZSe0mM+g0BgWAyCF/mFFYdfY0xHtqy0x
+QWkW9OR0KBl4JpphDDolHoNL3TLydH3t4inX8SAOpaUdsjMcIPKqjT1htQm0Pk5r
+vFYvKuVrxMnV0F+wMmZRuziKWrZlVDwBMfCAchzuVexDWfcjTmUQmhZxJuUzORw3
+swgh9HIpxjMkgdlHodbMAEpMIkkoeJnph3I9uTocXZbK/lAInggQdm0Q+on1ZT0A
+ljO/6jisDZzIguE4ZAQ2DfYsGI8H3tz/+76uIwwBNOmu0woUDSWXVcPWiviq49Bi
+GmH0KlUfWAphj86IfTWXT1HRay3eZQt3
+-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/root+server-crldir/a3d11bff.r0 b/src/test/ssl/ssl/root+server-crldir/a3d11bff.r0
new file mode 100644
index 0000000..5b42d38
--- /dev/null
+++ b/src/test/ssl/ssl/root+server-crldir/a3d11bff.r0
@@ -0,0 +1,11 @@
+-----BEGIN X509 CRL-----
+MIIBhTBvMA0GCSqGSIb3DQEBCwUAMEAxPjA8BgNVBAMMNVRlc3Qgcm9vdCBDQSBm
+b3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHN1aXRlFw0yMTAzMDMy
+MjEyMDdaFw00ODA3MTkyMjEyMDdaMA0GCSqGSIb3DQEBCwUAA4IBAQACkv0Nnerr
+ZkacIUbRaANYLIsYAGfKuBYDAp4I4CCC2hvXL64KLDMZbVfB4vp3hvM2FZdT2AwT
+SBNr2rpYp7Coc3GeCoWPcClgSrABD3Z5GY1YAdLGiXVKaH3CmdJTznhEPagE4z5R
+40qbmw8RU062ZbyFamBO7VTY7IFBA8PxuTgAH/3OYa5Jne8umyPQT5fKnqyRBz/A
+6/b5RCxuPOWFm0MJKrEaAeLk6eaCxUUqXQP+8mHscphqZTOynjAW0NPH+/x2NpxS
+/C5LTeOzJ28k8X434h323G18n/CFERWnhW1UyR1Pt6oSGMZqU5UwbSrwTsf8tSSc
++GrJP3XxJ1OC
+-----END X509 CRL-----
diff --git a/src/test/ssl/ssl/root+server-crldir/a836cc2d.r0 b/src/test/ssl/ssl/root+server-crldir/a836cc2d.r0
new file mode 100644
index 0000000..331a83c
--- /dev/null
+++ b/src/test/ssl/ssl/root+server-crldir/a836cc2d.r0
@@ -0,0 +1,11 @@
+-----BEGIN X509 CRL-----
+MIIBpTCBjjANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
+b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc2VydmVyIGNlcnRzFw0yMTAz
+MDMyMjEyMDdaFw00ODA3MTkyMjEyMDdaMBswGQIIICEDAxQSBwUXDTIxMDMwMzIy
+MTIwN1owDQYJKoZIhvcNAQELBQADggEBAJxj0taZYIIxUsCuXR5CN2OymjMvRwmV
++10VOkyBQ3VkzHlXeJkmZsU2Dvmc205l9OYouh/faL0TfK2NyhmBo+MrTizL9TBo
+4u2es/0oJGj2wyNMkRs0SlSJelakvGFBvSKfqoV0l2O1WDV7M4KtdC8ZVZipmL4R
+ac4hBMK0ifHuTS5Od6o0C2RijEPCHMXaS/LkWpBqcStI2oirhjo+Th1wxTMGUVFy
+imVvt6D6QqqHCUYrvcNEN0xBNFwJGq/0cgSy+w5szt/RRehmJKX8MbNeZxrznIIx
+B18ch9rbBltz+Y4R63rCN9MdsnGXf6PQ6a6doZhSI1pnDrui12MOQrU=
+-----END X509 CRL-----
diff --git a/src/test/ssl/ssl/root+server.crl b/src/test/ssl/ssl/root+server.crl
new file mode 100644
index 0000000..8b0c716
--- /dev/null
+++ b/src/test/ssl/ssl/root+server.crl
@@ -0,0 +1,22 @@
+-----BEGIN X509 CRL-----
+MIIBhTBvMA0GCSqGSIb3DQEBCwUAMEAxPjA8BgNVBAMMNVRlc3Qgcm9vdCBDQSBm
+b3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHN1aXRlFw0yMTAzMDMy
+MjEyMDdaFw00ODA3MTkyMjEyMDdaMA0GCSqGSIb3DQEBCwUAA4IBAQACkv0Nnerr
+ZkacIUbRaANYLIsYAGfKuBYDAp4I4CCC2hvXL64KLDMZbVfB4vp3hvM2FZdT2AwT
+SBNr2rpYp7Coc3GeCoWPcClgSrABD3Z5GY1YAdLGiXVKaH3CmdJTznhEPagE4z5R
+40qbmw8RU062ZbyFamBO7VTY7IFBA8PxuTgAH/3OYa5Jne8umyPQT5fKnqyRBz/A
+6/b5RCxuPOWFm0MJKrEaAeLk6eaCxUUqXQP+8mHscphqZTOynjAW0NPH+/x2NpxS
+/C5LTeOzJ28k8X434h323G18n/CFERWnhW1UyR1Pt6oSGMZqU5UwbSrwTsf8tSSc
++GrJP3XxJ1OC
+-----END X509 CRL-----
+-----BEGIN X509 CRL-----
+MIIBpTCBjjANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
+b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc2VydmVyIGNlcnRzFw0yMTAz
+MDMyMjEyMDdaFw00ODA3MTkyMjEyMDdaMBswGQIIICEDAxQSBwUXDTIxMDMwMzIy
+MTIwN1owDQYJKoZIhvcNAQELBQADggEBAJxj0taZYIIxUsCuXR5CN2OymjMvRwmV
++10VOkyBQ3VkzHlXeJkmZsU2Dvmc205l9OYouh/faL0TfK2NyhmBo+MrTizL9TBo
+4u2es/0oJGj2wyNMkRs0SlSJelakvGFBvSKfqoV0l2O1WDV7M4KtdC8ZVZipmL4R
+ac4hBMK0ifHuTS5Od6o0C2RijEPCHMXaS/LkWpBqcStI2oirhjo+Th1wxTMGUVFy
+imVvt6D6QqqHCUYrvcNEN0xBNFwJGq/0cgSy+w5szt/RRehmJKX8MbNeZxrznIIx
+B18ch9rbBltz+Y4R63rCN9MdsnGXf6PQ6a6doZhSI1pnDrui12MOQrU=
+-----END X509 CRL-----
diff --git a/src/test/ssl/ssl/root+server_ca.crt b/src/test/ssl/ssl/root+server_ca.crt
new file mode 100644
index 0000000..5074f4f
--- /dev/null
+++ b/src/test/ssl/ssl/root+server_ca.crt
@@ -0,0 +1,38 @@
+-----BEGIN CERTIFICATE-----
+MIIDHjCCAgagAwIBAgIUF+e8lCA0vD0zKtxIDVPdDY/IkgUwDQYJKoZIhvcNAQEL
+BQAwQDE+MDwGA1UEAww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCBy
+ZWdyZXNzaW9uIHRlc3Qgc3VpdGUwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIx
+MjA3WjBAMT4wPAYDVQQDDDVUZXN0IHJvb3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NM
+IHJlZ3Jlc3Npb24gdGVzdCBzdWl0ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBALZ81vKKBJlxgjwuNoK67I4IE9zfSLb0eHbgZwZxDVzdmFejARrHlWk3
++MK7Nav7RLSJ990am33zb58CTHc7YYVlBp07+PwLXzypqWkhYfok1OYYjyjCrFDs
+sjcJI3hRCZNEz+wYsG+tdYWJ+gRPQOWfh0YfO2rFgXAIMLiF6lyWzf1eOM+OjYrF
+/eyzwbMaJkkGa/AyZKz3wZiPq0jTuYLVmH4MK7MBOsUfSmsBsn/ohyRCQzM+ol0v
+Qlsrulj8usponRPDh9ng4PB5OSgR79YimQZnASQzJxiUvMADrKL5L6KwLxJlzbqY
+R0b5mLh8KBzBQmSh3Aj2e2I7Z17hdaMCAwEAAaMQMA4wDAYDVR0TBAUwAwEB/zAN
+BgkqhkiG9w0BAQsFAAOCAQEAY6h2MurDkE2LAG3TPhTrAczflR3np6y1cDxeRzRi
+br2bczXVfgWDsBZDhKXdIQldYQhAUU7u09GtAtujWnkJguPuVtlhEfuW/eXpcBI2
+XQnrkaTqjD/DDMJGijNVAXEHSecEls6uEuuSCxmm7hVD781Aqo0HlLPDhTEkko6r
+IYFO0QyFG+oFSVhUp2KuarQNHVgopOmWbtbrq2KqaL5Gm5AXPSRzEhIeobYdSnTe
+OCZhKLxVZiZmO71BBwsTgwtU58/G9e2ciGGdltI8ANlmVfdtwgRz3b7H9EUZat6s
+kubl/m5HWBsKJEWEzFWrWkQV3ipoTmorJ6KCGABBCeVYmg==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDFDCCAfygAwIBAgIIICEDAxQSBwAwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
+Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
+c3Qgc3VpdGUwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjBCMUAwPgYD
+VQQDDDdUZXN0IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qg
+c2VydmVyIGNlcnRzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4kp2
+GW5nPb6QrSrtbClfZeutyQnHrm4TMPBoNepFdIVxBX/04BguM5ImDRze/huOWA+z
+atJAQqt3R7dsDwnOnPKUKCOuHX6a1aj5L86HtVgaWTXrZFE5NtL9PIzXkWu13UW0
+UesHtbPVRv6a6fB7Npph6hHy7iPZb009A8/lTJnxSPC39u/K/sPqjrVZaAJF+wDs
+qCxCZTUtAUFvWFnR/TeXLWlFzBupS1djgI7PltbJqSn6SKTAgNZTxpRJbu9Icp6J
+/50ELwT++0n0KWVXNHrDNfI5Gaa+SxClAsPsei2jLKpgR6QFC3wn38Z9q9LjAVuC
++FWhoN1uhYeoricEXwIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB
+CwUAA4IBAQCdCA/EoXrustoV4jJGbkdXDuOUkBurwggSNBAqUBSDvCohRoD77Ecb
+QVuzPNxWKG+E4PwfUq2ha+2yPONEJ28ZgsbHq5qlJDMJ43wlcjn6wmmAJNeSpO8F
+0V9d2X/4wNZty9/zbwTnw26KChgDHumQ0WIbCoBtdqy8KDswYOvpgws6dqc021I7
+UrFo6vZek7VoApbJgkDL6qYADa6ApfW43ThH4sViFITeYt/kSHgmy2Udhs34jMM8
+xsFP/uYpRi1b1glenwSIKiHjD4/C9vnWQt5K3gRBvYukEj2Bw9VkNRpBVCi0cOoA
+OuwX3bwzNYNbZQv4K66oRpvuoEjCNeHg
+-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/root.crl b/src/test/ssl/ssl/root.crl
new file mode 100644
index 0000000..5b42d38
--- /dev/null
+++ b/src/test/ssl/ssl/root.crl
@@ -0,0 +1,11 @@
+-----BEGIN X509 CRL-----
+MIIBhTBvMA0GCSqGSIb3DQEBCwUAMEAxPjA8BgNVBAMMNVRlc3Qgcm9vdCBDQSBm
+b3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHN1aXRlFw0yMTAzMDMy
+MjEyMDdaFw00ODA3MTkyMjEyMDdaMA0GCSqGSIb3DQEBCwUAA4IBAQACkv0Nnerr
+ZkacIUbRaANYLIsYAGfKuBYDAp4I4CCC2hvXL64KLDMZbVfB4vp3hvM2FZdT2AwT
+SBNr2rpYp7Coc3GeCoWPcClgSrABD3Z5GY1YAdLGiXVKaH3CmdJTznhEPagE4z5R
+40qbmw8RU062ZbyFamBO7VTY7IFBA8PxuTgAH/3OYa5Jne8umyPQT5fKnqyRBz/A
+6/b5RCxuPOWFm0MJKrEaAeLk6eaCxUUqXQP+8mHscphqZTOynjAW0NPH+/x2NpxS
+/C5LTeOzJ28k8X434h323G18n/CFERWnhW1UyR1Pt6oSGMZqU5UwbSrwTsf8tSSc
++GrJP3XxJ1OC
+-----END X509 CRL-----
diff --git a/src/test/ssl/ssl/root_ca.crt b/src/test/ssl/ssl/root_ca.crt
new file mode 100644
index 0000000..5ee9870
--- /dev/null
+++ b/src/test/ssl/ssl/root_ca.crt
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDHjCCAgagAwIBAgIUF+e8lCA0vD0zKtxIDVPdDY/IkgUwDQYJKoZIhvcNAQEL
+BQAwQDE+MDwGA1UEAww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCBy
+ZWdyZXNzaW9uIHRlc3Qgc3VpdGUwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIx
+MjA3WjBAMT4wPAYDVQQDDDVUZXN0IHJvb3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NM
+IHJlZ3Jlc3Npb24gdGVzdCBzdWl0ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBALZ81vKKBJlxgjwuNoK67I4IE9zfSLb0eHbgZwZxDVzdmFejARrHlWk3
++MK7Nav7RLSJ990am33zb58CTHc7YYVlBp07+PwLXzypqWkhYfok1OYYjyjCrFDs
+sjcJI3hRCZNEz+wYsG+tdYWJ+gRPQOWfh0YfO2rFgXAIMLiF6lyWzf1eOM+OjYrF
+/eyzwbMaJkkGa/AyZKz3wZiPq0jTuYLVmH4MK7MBOsUfSmsBsn/ohyRCQzM+ol0v
+Qlsrulj8usponRPDh9ng4PB5OSgR79YimQZnASQzJxiUvMADrKL5L6KwLxJlzbqY
+R0b5mLh8KBzBQmSh3Aj2e2I7Z17hdaMCAwEAAaMQMA4wDAYDVR0TBAUwAwEB/zAN
+BgkqhkiG9w0BAQsFAAOCAQEAY6h2MurDkE2LAG3TPhTrAczflR3np6y1cDxeRzRi
+br2bczXVfgWDsBZDhKXdIQldYQhAUU7u09GtAtujWnkJguPuVtlhEfuW/eXpcBI2
+XQnrkaTqjD/DDMJGijNVAXEHSecEls6uEuuSCxmm7hVD781Aqo0HlLPDhTEkko6r
+IYFO0QyFG+oFSVhUp2KuarQNHVgopOmWbtbrq2KqaL5Gm5AXPSRzEhIeobYdSnTe
+OCZhKLxVZiZmO71BBwsTgwtU58/G9e2ciGGdltI8ANlmVfdtwgRz3b7H9EUZat6s
+kubl/m5HWBsKJEWEzFWrWkQV3ipoTmorJ6KCGABBCeVYmg==
+-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/root_ca.key b/src/test/ssl/ssl/root_ca.key
new file mode 100644
index 0000000..aa5f243
--- /dev/null
+++ b/src/test/ssl/ssl/root_ca.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAtnzW8ooEmXGCPC42grrsjggT3N9ItvR4duBnBnENXN2YV6MB
+GseVaTf4wrs1q/tEtIn33RqbffNvnwJMdzthhWUGnTv4/AtfPKmpaSFh+iTU5hiP
+KMKsUOyyNwkjeFEJk0TP7Biwb611hYn6BE9A5Z+HRh87asWBcAgwuIXqXJbN/V44
+z46NisX97LPBsxomSQZr8DJkrPfBmI+rSNO5gtWYfgwrswE6xR9KawGyf+iHJEJD
+Mz6iXS9CWyu6WPy6ymidE8OH2eDg8Hk5KBHv1iKZBmcBJDMnGJS8wAOsovkvorAv
+EmXNuphHRvmYuHwoHMFCZKHcCPZ7YjtnXuF1owIDAQABAoIBAQCiCzsHhf1NkBi4
+fcTT006JVKzmnbNBGtb5oIx7kNnv06oab9lkQUPwec5AhOLFA8tfkX/y61SVxBwj
+E3R5D9aqECqOZpnSnfqEsJeJjiYlbJ1McRR2el9vQK+D5W6EwVkCV8FWAhpyIJJR
+8VJ8jy+udzk00Dj/t8AXjn5M7EVOzu7fu2CIjJ2csE4NpWnn4eaDqev/brEVaLSP
+DGFdMw4D29AmErByN42d90U5YE2c1UufYoFL480qoA4pW5Tw5+vrIDliEHhnTtSN
+aTHZiOCmHtBFieQzmWCRQqmtlJP+7Z/NqK0i91HpjFrU5AuyLOMbqJPl6TgncNA+
+MSXMXGQBAoGBANlsAQc3poc3MX18++qgRJGqJCBF3MVQNnZQxmO6swydikZmlunN
+kmslheb/JZbE9tkjEhx1RuUeZIvOCxURdODDPnvm9bk0C7LvPGXnYLWTbCknHEwR
+8yIvPGiLhZOuDGAdLpHzG5F1eHQLOWQpTNndptlveSz5Zc0a+B7qmWYBAoGBANbe
+Atvo8JI+ht2tiidwCo5WHR26ux0yA+iHPNyMAEaY5KFblyvjb4rAFziUu6cLzFNl
+N2pdv3ZpIHs82erJMkCSrIbp9RM3TWaTMFgWETDnZ6dNclEsEva/kRJquOw+N/Ag
+LFOn8omVRMHq99G/eFdPeSYc1mDRNZ0vDstOA4OjAoGAd9l/X5kfpN2Z3FCvFRCv
+e5RMQbYBEos62lGAaq0Z0dRtyoz2l38IPSP8Ae+Xqtp8MAmTDDjhkZ8FUcOMfFqZ
+EOTPZsFTpnm4ETSrGIlI2A6hyrWSdaRXX/ql1ANE6LlCfSDY8P8PrUkR0vX09u+F
+O3thY+5833vC0CMTrwcm9AECgYBmVktqTiH2pY06m+MHMZf1fxJTDJL+Lsopv+++
+43dmKIAMUkFICAUiQqdMrZpKz5W7yqOAJ7J/RUbRK4RnDPjARJujjl7JjjdxOX13
+FtuNPUnjJ0HhY2qM12TTLr1w15lw5wH1vjIIUW30JmNuJRG+E/4Rpv58EmjEupsD
+Pd7ynQKBgQC42hGdd3TGe7zYqnPIe/vJyNX05xErKXK1iqwj6ZQWOiurGiePbiIu
+Top5MZcqLetZ9872efPLQFlkB2elCP91yBKNdI+onBcha9rVcczjCdaQswsm5Ws3
+58Dyjci4NqyD8B19AOJLTl5gq8pmj5Nom8ip+Bm2EsQw777Dqq9YrA==
+-----END RSA PRIVATE KEY-----
diff --git a/src/test/ssl/ssl/server-cn-and-alt-names.crt b/src/test/ssl/ssl/server-cn-and-alt-names.crt
new file mode 100644
index 0000000..12d1ec3
--- /dev/null
+++ b/src/test/ssl/ssl/server-cn-and-alt-names.crt
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDVTCCAj2gAwIBAgIIICEDAxQSBwAwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
+Aww3VGVzdCBDQSBmb3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHNl
+cnZlciBjZXJ0czAeFw0yMTAzMDMyMjEyMDdaFw00ODA3MTkyMjEyMDdaMEYxHjAc
+BgNVBAsMFVBvc3RncmVTUUwgdGVzdCBzdWl0ZTEkMCIGA1UEAwwbY29tbW9uLW5h
+bWUucGctc3NsdGVzdC50ZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAwVES+mD1iY1UBGWNLsuBxGkyOGTI1X/sXcCUZ7aLOGkXHYatiUTcIrSNNAS5
+yCvbq/A/C1NuDw59nrU2TitcLBx5AIhz74EV+xv/u/GuX0gvJzDWh/6EeMzDIcJL
+Iq7iEgO8ff5fuAzuwuNguZkX51JjBiXc2rtfgPI3CMU1lqCbb2vW9ZN4Pm7wRqvd
+d/F/mySiFmLFsB4HLhCGZN89vO4cbslN4+YrGKEcHeXGWRaxv6gSXbpEgUYpefzz
++QB7AepU5aWntm3X+E1we5AHLSKckwUdBuT5uYgmZcYA/kCC4/9RS02jTlu4Vfrd
+SemHwuo2UQ5ODJxzAhWrEl3F4QIDAQABo0swSTBHBgNVHREEQDA+gh1kbnMxLmFs
+dC1uYW1lLnBnLXNzbHRlc3QudGVzdIIdZG5zMi5hbHQtbmFtZS5wZy1zc2x0ZXN0
+LnRlc3QwDQYJKoZIhvcNAQELBQADggEBAG3dFQ/DqjFbjzIOni079R3I94lAZqbc
+cRUumDPSzihKwvCCnU5quqnYkOFISqBZsYmxR5fiHx4wT+jmWvLSltkaeS6gcGC1
+zuO8GFzL+PATUX63js8IfE3WYJE/bjmDVVzJOBArrbsExofdE2F2kkkLkjhk0ylg
+/TrAKtyqpsob0b4ZjMloR5JFHQXGHN/922x6Do1vduHMXlGckmR0sX6Mg/fiChVh
+vixUJje4W9ohft8G7lj3GnzI1gHEMp2PYKM+wqOug/gXEQuMIFlhjp2Mc6bAvFsD
+grgdAgcYUvgKukF9efJHq2V5XjqBWrmGAOQkiH1y+9gxhiHUiw+vojY=
+-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-cn-and-alt-names.key b/src/test/ssl/ssl/server-cn-and-alt-names.key
new file mode 100644
index 0000000..485e340
--- /dev/null
+++ b/src/test/ssl/ssl/server-cn-and-alt-names.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAwVES+mD1iY1UBGWNLsuBxGkyOGTI1X/sXcCUZ7aLOGkXHYat
+iUTcIrSNNAS5yCvbq/A/C1NuDw59nrU2TitcLBx5AIhz74EV+xv/u/GuX0gvJzDW
+h/6EeMzDIcJLIq7iEgO8ff5fuAzuwuNguZkX51JjBiXc2rtfgPI3CMU1lqCbb2vW
+9ZN4Pm7wRqvdd/F/mySiFmLFsB4HLhCGZN89vO4cbslN4+YrGKEcHeXGWRaxv6gS
+XbpEgUYpefzz+QB7AepU5aWntm3X+E1we5AHLSKckwUdBuT5uYgmZcYA/kCC4/9R
+S02jTlu4VfrdSemHwuo2UQ5ODJxzAhWrEl3F4QIDAQABAoIBADpFoQ3eKkVzV48X
+uW4QpCY7e4rqPmu06t/7zABTUzYG35Pj4+2L1zuS5zl17zZ6mfYDLk3QsU1SleVA
+RIVdpqQZVRQnDaN1atXNw9G4cVKBZM1QeGp3+yCawHstoQ5sXvMFM01bXykQpOwU
+NDTeBAmTmQviX+eDMa+h05sOLzAe5IfJd54au7jaDgX+J+OYoRcahXZLO3tco/kL
+Mo0OBj71ec8jrbhnViEXPwPUOBDoTJxfRotCZ2Sr0ozXT/sRBZvvK9OGzWf9mA2D
+M7UqbkKUL9AJxB+zTUILdM3+4buzifDZPUWe05dHyP6VAvtgSQJkdReFtUa868pm
+si+7Td0CgYEA+r4dxf880QW1hY/dpTfLXOcLKSHogIHv2Qt3Dinh4AthXZs91MQ9
+DMiT2x4RMGlk7zOu6Ua4HXjTT0s9CqUt9Cyga0zTn+XzNZxzcriRWYnw7pq0O77B
+3AODrK6/VajAjqdwiP3nQfBOyhz3G7YB2yXCpdnVVI179x8pbGnEP2MCgYEAxV64
+CaIW0hgwEZifT4PGINdGShk7ijQ0YhPw4bLJLV7gaPrKYG+qy8/R9AyhcFqz9MrF
+2E+jiD+fylNSLdkuR1/v6se1wWLjDiKip5F9molCAKTUBTkqD/8Ejh5+I7NAuFLA
+9QZYiaRLhIoVocWfzNIPHit7NZftaBtxTCtE8usCgYAmxbso4LzwvWdCTerCH4yM
+wxVQuPOQ24bRExrHz+YjlN7rcJPxEJ84GNP0MAQMbl+zNVS4sbzKoeJbApFf0gb3
+GOd9cBXRReeDxLt9Y9jl9ZSR8M4p5udnNAvqaeMgRcXwySd3p3tZEOW+DxiO6mgD
+ESW2K6b3OiGPJvxqzTgRbQKBgQDCvB/tMUY+6KqU0fdtpuCXio/JkHfUdomws2gZ
+6CLiZxgXvEptOABWs6e9mbC3gGbKAj+Om5UIW243XFpa7kvhFGFNTtqgAgdw7O97
+UeuRzBeZNwgSV0KPIdjGuINQig4zT0Me/rHgrH/uN6f8Q1bV6fQMmm4ohMwyydDR
+jGetHQKBgGLQf4MBNalhfnM7jnUCbA0ygrw7BuJRfwuamdcH9bdfOHMyrbOfZ+hS
+aKcOeaGi0HGOq+D2tIH1hmFYHD0klPgr/KWnNMoi2xTw+1GNKA2u9EZQQkK6XSRn
+Xb6zihNEqY8067K/um/658x1c9SbfvVmzjqo5OwgjSKygk6fXL8i
+-----END RSA PRIVATE KEY-----
diff --git a/src/test/ssl/ssl/server-cn-and-ip-alt-names.crt b/src/test/ssl/ssl/server-cn-and-ip-alt-names.crt
new file mode 100644
index 0000000..4e58c85
--- /dev/null
+++ b/src/test/ssl/ssl/server-cn-and-ip-alt-names.crt
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDLzCCAhegAwIBAgIIICERKRE1UQAwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
+Aww3VGVzdCBDQSBmb3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHNl
+cnZlciBjZXJ0czAeFw0yMTExMjkxOTM1NTFaFw00OTA0MTYxOTM1NTFaMEYxHjAc
+BgNVBAsMFVBvc3RncmVTUUwgdGVzdCBzdWl0ZTEkMCIGA1UEAwwbY29tbW9uLW5h
+bWUucGctc3NsdGVzdC50ZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEA6+8IYKAFnZ7V+fDo1cyMpbGBLzCfJOQ/1o2jOGP4+GjpsZgv6S6UT2MheC8M
+iiEFrYwdsSIZyYc3jEZrluy/UuR0bCGtqU92BCqa0iBLhvHOgjR588u253eLxQtQ
+8iJn11QPrKMk35nMkmY8GfHt4sGFbvBL6+GpipHq7a6cde3Z+v4kCB5dKMYDUDtm
+3mJmviuGNAu5wOqItk2Yi5dwJs1054007KNH0Il43urxiOfnkLS0cG5kehboPf86
+vxBt3iHByrU/9/DY5IvQCfSXVNa6rb5w5/pGja9aCei6Mv1jQY/V8SMQTga+MOsA
+0WB9akxMi2NxwS2+BQ4k/McPlwIDAQABoyUwIzAhBgNVHREEGjAYhwTAAAIBhxAg
+AQ24AAAAAAAAAAAAAAABMA0GCSqGSIb3DQEBCwUAA4IBAQAQLo2RzC07dG9p+J3A
+W6C0p3Y+Os/YE2D9wfp4TIDTZxcRUQZ0S6ahF1N6sp8l9KHBJHPU1cUpRAU1oD+Y
+SqmnP/VJRRDTTj9Ytdc/Vuo2jeLpSYhVKrCqtjqIrCwYJFoYRmMoxTtJGlwA0hSd
+kwo3XYrALPUQWUErTYPvNfDNIuUwqUXNfS0CXuIOVN3LJ+shegg6Pwbh9B5T9NHx
+kH+HswajhdpdnZIgh0FYTlTCPILDrB49aOWwqLa54AUA6WXa35hPsP8SoqL9Eucq
+ifPhBYyadsjOb+70N8GbbAsDPN1jCX9L8RuNcEkxSCKCYx91cWXh7K5KMPuGlzB7
+j8xB
+-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-cn-and-ip-alt-names.key b/src/test/ssl/ssl/server-cn-and-ip-alt-names.key
new file mode 100644
index 0000000..837eef9
--- /dev/null
+++ b/src/test/ssl/ssl/server-cn-and-ip-alt-names.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEA6+8IYKAFnZ7V+fDo1cyMpbGBLzCfJOQ/1o2jOGP4+GjpsZgv
+6S6UT2MheC8MiiEFrYwdsSIZyYc3jEZrluy/UuR0bCGtqU92BCqa0iBLhvHOgjR5
+88u253eLxQtQ8iJn11QPrKMk35nMkmY8GfHt4sGFbvBL6+GpipHq7a6cde3Z+v4k
+CB5dKMYDUDtm3mJmviuGNAu5wOqItk2Yi5dwJs1054007KNH0Il43urxiOfnkLS0
+cG5kehboPf86vxBt3iHByrU/9/DY5IvQCfSXVNa6rb5w5/pGja9aCei6Mv1jQY/V
+8SMQTga+MOsA0WB9akxMi2NxwS2+BQ4k/McPlwIDAQABAoIBAQCuNFKVNdKvrUYF
+RLJGmsAG3+eo9lern7TbML2ht39vu9dBwEMwA6qSa3mdCfBSVUuh9uE9lxY/TU3g
+j2aFi81A4VptNPjLGNblAKhMGnhp7UUzspeRQYuNoSFcnpxoDKtrvK/OIq/pQeBh
+AIfECHRDh+yEG32Tb44FuPQkB1eTYl8xbMEImrhNUaSjJk7tTsmydHy0DjmqHVKX
+HUj0TREfDBDOBiHtY0XV6Pu3bnqDH/TKLTfUf3UdfTuay3Yai9aEcRPWp9GrMO7G
+axsKCifTz6177gyr6Fv8HLeMZMh9rMZRn3e0zfaF6vrH1QnZZOts5jpUa0KugSCd
+//uC0iNxAoGBAPXVc3b+o3hY5gcwwpaW6JtsarDrmNRxrizqIDG7NgpqwdFXgTi6
+6q0t2pjv81ATqij69IcPkNSissyR4OEKnu/OFJWzreg8yLi75WHKi0E/6msHpwRk
+d1yP0Zgd05ots/yOjDSp593RagaPVvHBxMECZ/Tm3B+Tq55Azudd/zvLAoGBAPWw
+xf0oUEJl6NdUZD6K7eFc6jf8yrpD85dldeko6LeN8x0XlKKWvUDJ2+3oizXoQvCm
+8by6KOYEIo4MrtXuy9MmtPWfNvRBr+hsUHchIj7IgFa9bKXyK2FnJqu/8CbEymli
+eZu7hoOhelurhnFy1zSqwNO4GC+kw60Y/BO3Z1nlAoGAVOyYJtNwxXJwhKtjjYI0
+ePzLHrNE6J8c/Ick+AkkchTPP/JqwZ5Q0+KzUYITG+avMdkAAGhwMATEn8cFWLjC
+jzUyB0U7Hq9g5/CBHXdLBA+Ae9j46ZuLYH6OeW5UWz7OnsDfzpGjeA2QAxQhhQLb
+ZZHfN8tI39+zucfJskPWmGECgYEAg9guF1Fn6InJrqwR82IYj6SN6CeXHufSM392
+C/4xDDd3rDf4QlwECV2J0RzGf9I5Ae2EshNwWScE6Be0RweTh6cw2tJq6h7J6D8f
+2x4Dw49TF7klMdRIJUf2f5pLpHJccLswqTqzz7V69PCSABVxmUi8m6EiEYconp5W
+v7nfE2UCgYALrEqzncuSIX3q6TVAjnzT7gO4h8h2TUekIWdHQFldFx8R7Kncggnd
+48gQqhewchNR83UCcd7pPsCcTqu6UR1QRdq/DV5P6J3xdZ2iS/2gCM6hvWIvKZEv
+/ClnkyFCOW7zX6RKIXtRYZTV1kz3TajApi34RTIeIMTieaCarnBJbA==
+-----END RSA PRIVATE KEY-----
diff --git a/src/test/ssl/ssl/server-cn-only.crt b/src/test/ssl/ssl/server-cn-only.crt
new file mode 100644
index 0000000..acdf6f1
--- /dev/null
+++ b/src/test/ssl/ssl/server-cn-only.crt
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDAzCCAesCCCAhAwMUEgcBMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
+c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBzZXJ2ZXIg
+Y2VydHMwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjBGMR4wHAYDVQQL
+DBVQb3N0Z3JlU1FMIHRlc3Qgc3VpdGUxJDAiBgNVBAMMG2NvbW1vbi1uYW1lLnBn
+LXNzbHRlc3QudGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANWz
+VPMk7i5f+W0eEadRE+TTAtsIK08CkLMUnjs7zJkxnnm6RGBXPx6vK3AkAIi+wG4Y
+mXjYP3GuMiXaLjnWh2kzBSfIRQyNbTThnhSu3nDjAVkPexsSrPyiKimFuNgDfkGe
+5dQKa9Ag2SuVU4vd9SYxOMAiIFIC4ts4MLWWJf5D/PehdSuc0e5Me+91Nnbz90nl
+ds4lHvuDR+aKnZlTHmch3wfhXv7lNQImIBzfwl36Kd/bWB0fAEVFse3iZWmigaI/
+9FKh//WIq43TNLxn68OCQoyMe/HGjZDR/Xwo3rE6jg6/iAwSWib9yabfYPKbqq2G
+oFy6aYmmEquaDgLuX7kCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEA2AZrD9cTQXTW
+4j2tT8N/TTc6WK2ncN4h22NTte6vK7MVwsZJCtw5ndYkmxcWkXAqiclzWyMdayds
+WOa12CEH7jKAhivF4Hcw3oO3JHM5BA6KzLWBVz9uZksOM6mPqn29DTKvA/Y1V8tj
+mxK/KUA68h/u6inu3mo4ywBpb/tqHxxg2cjyR0faCmM0pwRM0HBr/16fUMfO83nj
+QG8g9J/bybu5sYso/aSoC5nUNp4XjmDMdVLdqg/nTe/ejS8IfFr0WQxBlqooqFgx
+MSE+kX2e2fHsuOWSU/9eClt6FpQrwoC2C8F+/4g1Uz7Liqc4yMHPwjgeP9ewrrLO
+iIhlNNPqpQ==
+-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-cn-only.key b/src/test/ssl/ssl/server-cn-only.key
new file mode 100644
index 0000000..672d3f0
--- /dev/null
+++ b/src/test/ssl/ssl/server-cn-only.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEA1bNU8yTuLl/5bR4Rp1ET5NMC2wgrTwKQsxSeOzvMmTGeebpE
+YFc/Hq8rcCQAiL7AbhiZeNg/ca4yJdouOdaHaTMFJ8hFDI1tNOGeFK7ecOMBWQ97
+GxKs/KIqKYW42AN+QZ7l1Apr0CDZK5VTi931JjE4wCIgUgLi2zgwtZYl/kP896F1
+K5zR7kx773U2dvP3SeV2ziUe+4NH5oqdmVMeZyHfB+Fe/uU1AiYgHN/CXfop39tY
+HR8ARUWx7eJlaaKBoj/0UqH/9YirjdM0vGfrw4JCjIx78caNkNH9fCjesTqODr+I
+DBJaJv3Jpt9g8puqrYagXLppiaYSq5oOAu5fuQIDAQABAoIBAELaJRsjVHehgpAG
+NhOXo5eUA3Kt7Y58CPRc4Ns669iI00DVaoqRAKgCuJ4ORTSCKATJIUnSrJZNnlaF
+GKzzVc0tLtGxLxisLZu7cQ6bXe8GtOc9lo9zmjY2LOZsdNTu0tKIePGKiQvFGust
+fcNlnkliYJSKmH3PdVSLEYHdBOmznMR+M5nif33OmuK+LIQ8Go+jpahvqXSG60ae
+QAKlJCO9DARjhJqpYw1GgtzXSxpiVWBkJzIwnemOecgBtm6W/5GDzYPq9GE5lY7N
+MTjP9BmnpMC1gPQjiDICrd9eWSUv6fuHAClCi5lMDrktWvZcEB0tpoxcQZf2d0/m
+vRZK7uECgYEA8fKpaDaZqPNktgLsrlo35wmHa3tkWR1jmI5DY5BHoO+N+Bm/ISwP
+HHLTObXmgzbycA5OEsIeUdb8ZmO79WINb9Z8aAmhft6bBzY7xZRNSouq0G/IgzZn
+m9D6f4ivBDXs8lZpJe3/SrvfCmnxPBO/vzezX6FqiPV24jSXNYcb+B0CgYEA4hyu
+bbO7Mfd1NmlJO+OWmAJBqJQKmFByP6uraUX9cgS2F+jexsyX12WGMXRoQM4CAo5u
+CN29U9NyokpZmifUbKq7cZ4Hni5ag+Wt9a/kuevmv8ysYEzVY07gjwg51z2uXV54
+wBA0nQsT28RVdNAv36hMhqgMM1ZTNa4AXGdxi00CgYEAzJRqKENaxKAhfUGVzYtd
+j47gIcLxQ+T0zQ8l7i8WUf+dJLbohO0TTfPNpROo+TRh5NxDqdrX9k15mD4mtUMW
+p4VOJk5WbsddgMib2+IdRLY6VgrfGgvLqdYXqfTyP/Y1B2iHeln2rsOSweR45Vqx
+nMdFdcwwH+SmhHkBjnJS9QUCgYBlmm/C+dVvMXwpFAyFbdI4wiLQ5p0QLm34MGLY
+7kth1b4hZlHc0QiWEJfJVz6ViDyc+3V0ZHdz2HsVdAVpYOZyYhHSjylrKfcgd6/A
+y+YiqV9J5mW67Cui8Um03ARptNzKNe5al62ct+KXiVTBJd+tR8oDZDX/R5Yic+rT
+muQJrQKBgDCc6inyAzBN6mwEcFJCj4JBoIBiTfcwX+Rruh4gR8+7KbiG3UqaXSiO
+prONCswe6sXs6s6bFCZSOwgsom/bYloBZRVtTPJv031VDTFUQBo4956/7dhIDdvC
+2ZDBwgHPeywPPK0OrGBuAXzfIS0YqMZeEXtpSdw8A3seQ2398/ir
+-----END RSA PRIVATE KEY-----
diff --git a/src/test/ssl/ssl/server-crldir/a836cc2d.r0 b/src/test/ssl/ssl/server-crldir/a836cc2d.r0
new file mode 100644
index 0000000..331a83c
--- /dev/null
+++ b/src/test/ssl/ssl/server-crldir/a836cc2d.r0
@@ -0,0 +1,11 @@
+-----BEGIN X509 CRL-----
+MIIBpTCBjjANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
+b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc2VydmVyIGNlcnRzFw0yMTAz
+MDMyMjEyMDdaFw00ODA3MTkyMjEyMDdaMBswGQIIICEDAxQSBwUXDTIxMDMwMzIy
+MTIwN1owDQYJKoZIhvcNAQELBQADggEBAJxj0taZYIIxUsCuXR5CN2OymjMvRwmV
++10VOkyBQ3VkzHlXeJkmZsU2Dvmc205l9OYouh/faL0TfK2NyhmBo+MrTizL9TBo
+4u2es/0oJGj2wyNMkRs0SlSJelakvGFBvSKfqoV0l2O1WDV7M4KtdC8ZVZipmL4R
+ac4hBMK0ifHuTS5Od6o0C2RijEPCHMXaS/LkWpBqcStI2oirhjo+Th1wxTMGUVFy
+imVvt6D6QqqHCUYrvcNEN0xBNFwJGq/0cgSy+w5szt/RRehmJKX8MbNeZxrznIIx
+B18ch9rbBltz+Y4R63rCN9MdsnGXf6PQ6a6doZhSI1pnDrui12MOQrU=
+-----END X509 CRL-----
diff --git a/src/test/ssl/ssl/server-ip-alt-names.crt b/src/test/ssl/ssl/server-ip-alt-names.crt
new file mode 100644
index 0000000..8a1bc62
--- /dev/null
+++ b/src/test/ssl/ssl/server-ip-alt-names.crt
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDCTCCAfGgAwIBAgIIICERKREEUAAwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
+Aww3VGVzdCBDQSBmb3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHNl
+cnZlciBjZXJ0czAeFw0yMTExMjkxOTA0NTBaFw00OTA0MTYxOTA0NTBaMCAxHjAc
+BgNVBAsMFVBvc3RncmVTUUwgdGVzdCBzdWl0ZTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBAOM8yB6aVWb17ujr3ayU62mxHQoqn4CvG9yXlJvGOGv/ursW
+Vs0UYJdc96LsNZN1szdm9ayNzCIw3eja+ULsjxCi6+3LM4pO76IORL/XFamlTPYb
+BZ4pHdZVB0nnZAAnWCZPyXdnjOKQ5+8unVXkfibkjj8UELBJ2snehsOa+CTkOBez
+zxYMqxAgbywLIYsW448brun7UXpWmqbGK+SsdGaIZ5Sb7Zezc5lt6CrLemTZTHHK
+7l4WZFCCEi4t3sgO8o1vDELD/IE5G8lyXvIdgJg6t8ssper7iCw6S8x+okhjiSjT
+vDLU2g4AanqZRZB49aPwTo0QUcJA2BCJxL9xLy8CAwEAAaMlMCMwIQYDVR0RBBow
+GIcEwAACAYcQIAENuAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQsFAAOCAQEAwZJ+
+8KpABTlMEgKnHIYb35ItGhtFiTLQta9RkXx7vaeDwpOdPP/IvuvpjpQZkobRgBsk
+bNM0KuJpd2mSTphQAt6eKQIdcPrkzvc/Yh9OK3YNLUAbu/ZhBUnBvFnUL4wn2f1U
+mfO+m8P/LxybwqKx7r1mbaB+tP3RTxxLcIMvm9ECPQEoBntfEL325Wdoj+WuQH5Y
+IvcM6FaCTkQsNIPbaBD5l5MhMLHRULZujbDjXqGSvRMQfns6np/biMjNdQA8NZ5z
+STeUFvkQbCxoA0YYLgoSHL5KhZjXrg2g+T+2TUyCTR/91xf9OoOjBZdixR0S0DzJ
+B1+5vnUjZaCfnSEA7A==
+-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-ip-alt-names.key b/src/test/ssl/ssl/server-ip-alt-names.key
new file mode 100644
index 0000000..b210b3a
--- /dev/null
+++ b/src/test/ssl/ssl/server-ip-alt-names.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpQIBAAKCAQEA4zzIHppVZvXu6OvdrJTrabEdCiqfgK8b3JeUm8Y4a/+6uxZW
+zRRgl1z3ouw1k3WzN2b1rI3MIjDd6Nr5QuyPEKLr7cszik7vog5Ev9cVqaVM9hsF
+nikd1lUHSedkACdYJk/Jd2eM4pDn7y6dVeR+JuSOPxQQsEnayd6Gw5r4JOQ4F7PP
+FgyrECBvLAshixbjjxuu6ftRelaapsYr5Kx0ZohnlJvtl7NzmW3oKst6ZNlMccru
+XhZkUIISLi3eyA7yjW8MQsP8gTkbyXJe8h2AmDq3yyyl6vuILDpLzH6iSGOJKNO8
+MtTaDgBqeplFkHj1o/BOjRBRwkDYEInEv3EvLwIDAQABAoIBACp3uY6+mSdc3wF4
+0zzlt/lQuHSl8plCIJrhWUyjhvfoGyXLzv0Uydh/72frbTfZz1yTSWauOXBKYa6a
+/eqb+0DIsf8G8uLuTaqjsAWKVOoXkoKMGkistn7P9UTCkdXVhIvkbWp7V8EgA7iX
+pZ/fzBPIsyzmuxe3NcR0ags0cxuxkNuu+YXDv1oTedmT2wS3CZq1d/T1Y/EOVIf8
+Iznd2aOverlsnt6iiQ3ZWdG/W5F8FhnrR/rrBdYsdCv6TH/KUYexnDOUYpayjDbu
+oAKnifPp6UqiOM4SuBL83OAz19jptp5vpF370BEVRs3eK0q+zo/mETjv9HsXdolZ
+lfoXA0ECgYEA/7nb2azbq/2muvXCh1ZxCEbn3mt8KXoJP/xkx/v9eEc/cc5Q9e0V
+2oGfjC2hSE+bjOWMwiUMD6uU+iRjhz5A3IvUxnoSdoL7H9p0hTqLMyP7dTDkoVF5
+aEuLMaiI5YEnfAFu9L5h8ZKieoQTBoscT06wnGjh9pBV9bthfTKA7ksCgYEA43sb
+55m9WL4kWCPwOAp3vdEAFyxzmZHlO26sEQOU/m5aN01pumYybBruziEXMI96yfTj
+VmXKReeYb6XUiCcs3fLSipD/+8/8CsjO4uMORtxWumXe8AbKZfysGFzL7wJlByGT
+38AGQwIG/XD8cKnaiEMX4E/3Owbcoxwixo3WZC0CgYEAovaqJ9mEU+Jc8h/TS7PG
+bGPjN1Z/1V6zrlcFUnw/Vvrwb3HvHglsN8cLCaW6df5lPjC6tq4tNX8+fPnbg0Ak
+zWc+vQzl3ygxKGdqgcyBEKIJiPETgcoN+GzL02V3d+oKY3f2YXlBqVSsvi6UgUL9
+U3zuB36/IQVyAhrbUZFxoGkCgYEAnaFAO+Nvrp/LhXwZyGuQf+rkmipGTIMpil5t
+QzjtNMV5JFszSWPpyrl7A0Ew1YiG+I0GP2c3m+sY2TzbIiGrWH0b4cMKbw63Qy3V
+FqlpyjaCrpVKv56k/7jv883RzuQk56Uf1+szK5mrCFITy2oXsVZ0pA4lbjSaDTjA
+7D968V0CgYEA+qKqXKL98+c5CMPnpf+0B1x2zgyUym1ouPfon2x5fhK84T53zDMA
+zfdUJ/SOZw6/c9vRF7RL8h+ZfFdIyoAXv4Tt6mIiZe7P+AUVg6XgJ0ce2MUSeWjI
+W8D4WdSi0jyqr99TuVBWhbTZJviMB3pHqKaHQ07hnd/lPtvzsiH12qk=
+-----END RSA PRIVATE KEY-----
diff --git a/src/test/ssl/ssl/server-ip-cn-and-alt-names.crt b/src/test/ssl/ssl/server-ip-cn-and-alt-names.crt
new file mode 100644
index 0000000..2be02fe
--- /dev/null
+++ b/src/test/ssl/ssl/server-ip-cn-and-alt-names.crt
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDHTCCAgWgAwIBAgIIICIBBBQ2MQAwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
+Aww3VGVzdCBDQSBmb3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHNl
+cnZlciBjZXJ0czAeFw0yMjAxMDQyMjM2MzFaFw00OTA1MjIyMjM2MzFaMDQxHjAc
+BgNVBAsMFVBvc3RncmVTUUwgdGVzdCBzdWl0ZTESMBAGA1UEAwwJMTkyLjAuMi4x
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwmqTdQJfs2Ti9tPitYp2
+27I0HvL/kNSgA6egFr0foRo0BorwJNIzdbV0+EnsfiBNTWL5It26gqO7UP3ms8t2
+vHD5gkXfT+f6ts0lVJEcIOkUD/8ws4Ic9Y4uPqb4gN+pUKqcxtmLW1TYk84MBK59
+Xz4yPPS6N+G/DMMeFHTNkM9EQwn/+DC3fDsWdGYM2GRWDTJGg1A5tSUcF+seu7i1
+Vg7XajBfsvgAUAsrAxV+X/sLZh94HY+paD6wfaI99mY2OXVc/XW/z1r9WQznor65
+ZkonNCaPfavqPG5vqnab9AyQcqPqmX8hf/xrniASBAkqNCctbASrFCIYvCJfGfmX
+EQIDAQABoyUwIzAhBgNVHREEGjAYhwTAAAIChxAgAQ24AAAAAAAAAAAAAAABMA0G
+CSqGSIb3DQEBCwUAA4IBAQBf7kmYfRYfnWk1OUfY3N1kaNg9piBBlFr9g+OQn9KU
+zirkN7s0ZQbCGxV1uJQBKS58NyE414Vorau77379emgYDcCBpDIYpkLiNujVrIOr
+ggRFKsFRgxu4/mw0BSgCcV8RPe9SWHZ90Mos7TMCnW/PdxOCD1wD0YMkcs0rwB3l
+0Kzc7jDnfOEvmgw/Ysm7v67ps+05Uq5VskQ6WrpSAw6kPD/QMuuBAX8ATPczIaox
+zAMyncq1IiSIwG93f3EoQQThdQ70C6G9vLcu9TtL6JAsEMFEzR99gt1Wsqvmgl9W
+kStzj1yjIWeo5gIsa4Jgcke1lZviWyrTxHDfyunYE5i5
+-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-ip-cn-and-alt-names.key b/src/test/ssl/ssl/server-ip-cn-and-alt-names.key
new file mode 100644
index 0000000..54fe80f
--- /dev/null
+++ b/src/test/ssl/ssl/server-ip-cn-and-alt-names.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAwmqTdQJfs2Ti9tPitYp227I0HvL/kNSgA6egFr0foRo0Borw
+JNIzdbV0+EnsfiBNTWL5It26gqO7UP3ms8t2vHD5gkXfT+f6ts0lVJEcIOkUD/8w
+s4Ic9Y4uPqb4gN+pUKqcxtmLW1TYk84MBK59Xz4yPPS6N+G/DMMeFHTNkM9EQwn/
++DC3fDsWdGYM2GRWDTJGg1A5tSUcF+seu7i1Vg7XajBfsvgAUAsrAxV+X/sLZh94
+HY+paD6wfaI99mY2OXVc/XW/z1r9WQznor65ZkonNCaPfavqPG5vqnab9AyQcqPq
+mX8hf/xrniASBAkqNCctbASrFCIYvCJfGfmXEQIDAQABAoIBAB6GgVST5NbT9lbu
++d+rN/JSzqA1Yy8oU19/iEFJvJec96I3WnFNl8rZjN4XLUy4YarO6XMyAUDV2Gll
+FD4Sqjf4PRTZR7DSKaleGIhoqFP6hK3mUY091rIves9XhBkoBPunbipCqgDTF5ZN
+edGaXBECQP0VJ8/yX/7u++AWXthnjDis9X0taZfFg/PYbV7SCJ1Hg1O/wEsgXlnC
+7mbL6wkCW0f6700B0x1kKbZqJY95xRqp6Ipq2lIQbJDdGywoj0WzKqNltf9cer+r
+cXl8WjeiMvvvpl4uGhckAbzUifUzxN6A3f1fu/XKtOmabMi9t7J4MRfgOgedgtQB
+0jaZGSkCgYEA+lBLnNY6M48HX2mdtr86+n41gh69v8Z7oNikJFDZkodrvI8uqE0i
+0XwnYPFddt8NbmuUhhuzI2M8RKhGLgdlbKpkSSVafnMfcxRmX2EAtWQgdvX1Iult
+752LWdBgSuw2vlzvy3T/GYnjMrXSCGput4amqojMEbvUGvIdSUMdHGMCgYEAxtU1
+WixKPL6aEnYy1f4bybzcNgGtl8PBRz9xw+P46g+ijOPoaG9O73Tr7An11AO003Ot
+DHhMW+b8yHLyxoKwS2sU2cN/lKB8xNQYZc1D61RNJlzgnHMXnA0lcH0I3M35fqKr
+/71pD1ZP40SSJS+od/KEjW80XzuOdyiXg8q81vsCgYEAnUPLbbsuj+whzrFVlFZr
+IKwgxCK6Rn3WeIUEA4kEWUpZxvsSbk0gPgtJ1l9uwFt9Xc2bX/KRRv93Aw/SH+Mn
+tvEK1uXwCBgePzgm5W/VeSFyQCthm1CbcHtD7Oa9SPVFo65SPjrAd3QpWVfgoMb1
+zrp7hhMyW0XuCgvpmHjhFk8CgYEAxq/thXM2p+bLLWGhwQcRG5G299zLbBl4PUsf
+0uEvLi17gJCKADoiRdSvoAn/9eHSQ26XYRuhKkDzHxcGlOmpY2PYzRa3mXyZ0VIk
+Iy5wDWwLQCeVZ6D22cClRfgb8BF/nFTPzVmn72SPpgoyhChQj7PvUynpyrRH07jj
+VxYziBsCgYAFr37Xbl0VnXVK+XU+vMwUZjcF4jpoCr7SFZqgRbW2GbYSUoMuPXns
+RnJh+Fvi1NUei+E5s1H4P1pVq4p0jFxP4GvH/qvNjnIn/Er3bbqvpox6dWUJXprq
+qTQSDIeoDC/V8cyRoIfqPvTVqY8Rgew6GEkv0bAImdxhoSng7vIseg==
+-----END RSA PRIVATE KEY-----
diff --git a/src/test/ssl/ssl/server-ip-cn-and-dns-alt-names.crt b/src/test/ssl/ssl/server-ip-cn-and-dns-alt-names.crt
new file mode 100644
index 0000000..23c06da
--- /dev/null
+++ b/src/test/ssl/ssl/server-ip-cn-and-dns-alt-names.crt
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDQzCCAiugAwIBAgIIICIBBBQ2MQEwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
+Aww3VGVzdCBDQSBmb3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHNl
+cnZlciBjZXJ0czAeFw0yMjAxMDQyMjM2MzFaFw00OTA1MjIyMjM2MzFaMDQxHjAc
+BgNVBAsMFVBvc3RncmVTUUwgdGVzdCBzdWl0ZTESMBAGA1UEAwwJMTkyLjAuMi4x
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8xddbo/x2TOSIa/br8BN
+o/URdTr9+l2R5YojiZKDuLxiQVkgC30PJ2/CNFKIh2nHhRrzknI6sETVtrxZ+9V2
+qRc1yShVu462u0DHPRMIZnZIOZg3hlNB0cRWbOglUKlttIARNEQUcTUyPOtyo4/v
++u0Ej5NTNcHFbFT01vdD9MjQiCO3jKdAwPIb14jTg4C71EpZ+LuelDo4DzF2/XgG
+WqUTrgD/XnBU/60PU9Iy3G0nVpx21q6ppn9G7a9R+i8FjBcwW1T+cfsBDWhAv+bi
+RmSAkENf8L8TwOlDQUwROkfz3Hz36vuJjdkreQJsiqL0HnrnH5T5G9UzJO86FvZQ
+5wIDAQABo0swSTBHBgNVHREEQDA+gh1kbnMxLmFsdC1uYW1lLnBnLXNzbHRlc3Qu
+dGVzdIIdZG5zMi5hbHQtbmFtZS5wZy1zc2x0ZXN0LnRlc3QwDQYJKoZIhvcNAQEL
+BQADggEBAF+mfaw6iBPzpCgqq830pHRa3Yzm1aezt8SkeRohUYHNv/yCnDSRaqtj
+xbENih3lJMSTBL3g0wtTOHfH8ViC/h+lvYELHzXKic7gkjV7H5XETKGr0ZsjBBT2
+4cZQKbD9e0x0HrENXMYgGpBf747qL6uTOVJdG0s15hwpLq47bY5WUjXathejbpxW
+prmF8F+xaC52N9P/1VnqguQB909F4x1pyOK7D7tjFu+Y8Je7PHKbb6WY5K6xAv6t
+R17CY0749/FotlphquElUR2bs5Zzv5YrjUHPTcbwKvcH5cdNi93/u6NJt2xNAoYf
+aZERhX5TA9DYk4gC8OY0yGaYCIj3Dd4=
+-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-ip-cn-and-dns-alt-names.key b/src/test/ssl/ssl/server-ip-cn-and-dns-alt-names.key
new file mode 100644
index 0000000..0ace41e
--- /dev/null
+++ b/src/test/ssl/ssl/server-ip-cn-and-dns-alt-names.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEA8xddbo/x2TOSIa/br8BNo/URdTr9+l2R5YojiZKDuLxiQVkg
+C30PJ2/CNFKIh2nHhRrzknI6sETVtrxZ+9V2qRc1yShVu462u0DHPRMIZnZIOZg3
+hlNB0cRWbOglUKlttIARNEQUcTUyPOtyo4/v+u0Ej5NTNcHFbFT01vdD9MjQiCO3
+jKdAwPIb14jTg4C71EpZ+LuelDo4DzF2/XgGWqUTrgD/XnBU/60PU9Iy3G0nVpx2
+1q6ppn9G7a9R+i8FjBcwW1T+cfsBDWhAv+biRmSAkENf8L8TwOlDQUwROkfz3Hz3
+6vuJjdkreQJsiqL0HnrnH5T5G9UzJO86FvZQ5wIDAQABAoIBAGv0BFoFMrHyZQLw
+xe7Wx6P4QTh+aiu1QgVdw0pk9nojrr62hbSUZRZuWyBBRsBcCW7i+Sgf8lA1QXNV
+UeC0e228EPa0It6YEi42JkTJHwHhpVFud7n/X0t4lajnryqTE1UFSp6bXTipFxZW
+uSJJ2ZjliRD5rApDcxkY4WJVjKg3aEt7P/DiM8iKGfyE6stq72VjEbJjdViMEcOP
+BNf0TiREZz5Mp7jAVWhpen0ebbLOBVWV4/ONNcL+yqR4mCEDUSFGewrTVX4zHL0A
+hYk198C5F8sFvEDnFkPco9sXMVanmLoI8sbhP4IIz9g4+GU6kFuj7fUKp11Azqv+
+3WQDKYECgYEA/XG4mmG/g8FG44y42mfZpUXWi1pwU4CQIrhkoU5j7EPQrvRboOOE
+Rv95jSwyZu4vCqjyI5FN1jCGTdhmt++R1e//zH6Hqa9Smo+jw7DtAFrCYd1JnCf1
+ToOwsYPHv4P7A8q8kc5vCNIv+AQSlP/wqdVNo3grdf7cGXkMtEY4F9UCgYEA9Yrq
+zWdnNGPATuSBqL6TSjQ37oR+dBD6WnGsiDenQkOzyDPFZ3CT1DjJghjEtxc8EfNf
+Oo8dMMR2q+5FZQo7WuqONEgyzKePiNR8RK2gOYpgdjN9bih1sAhHR10D26cpwlDJ
+bx7D5ZzENLbdZmfEiWwKswnaIhN4yMalgE0mP8sCgYAhzJy12ftUct4lUosEdX0N
+EXc/NlxshmSyfKzO5kllJNYbvvLJTg5B+agYL6C5IWKcpVNFcwdSXT5L+2QXe5eT
+VGJkvysQchUuD6HjYyD4PyJVMtGyRZHtWpqh0dU9sTg0lUD4oPMl1gIXrVNdE5Tg
+0VV9S3VgUxC/ROlw0TyB0QKBgGsVE0NS9hJF8mc1hko2GnwA++d8Rr2NbfElo+2f
+/8SJTA1ibpOm6AFkZpTjAl8qtdrKPVyHb16GP47Jkd/3r1z979hjKCxSYul0aWF2
+KusNKvZBjFEPOgv0AEniCb2wUCjbHI3mZ95qGLM4kKOJW4/m21+rS0MTJNjCsQic
+HLMzAoGAeCsY09d3m8xGeU+DuTPC6GH7Sgy/NBYqS5VaVNjb2jnuZlW2SSW2oiID
+4tXTi4ruKmHC898BfyFxhSMqub+tg3pVqIYADC71rnJLrVyc1SzoWzL7yMT3qFj7
+C7ZYZYmfG9agcZb5NkqKPTfCxkBhWbdgTTgBKVO/xQst8EUgko8=
+-----END RSA PRIVATE KEY-----
diff --git a/src/test/ssl/ssl/server-ip-cn-only.crt b/src/test/ssl/ssl/server-ip-cn-only.crt
new file mode 100644
index 0000000..9bf015c
--- /dev/null
+++ b/src/test/ssl/ssl/server-ip-cn-only.crt
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC8TCCAdkCCCAhESkRN1IAMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
+c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBzZXJ2ZXIg
+Y2VydHMwHhcNMjExMTI5MTkzNzUyWhcNNDkwNDE2MTkzNzUyWjA0MR4wHAYDVQQL
+DBVQb3N0Z3JlU1FMIHRlc3Qgc3VpdGUxEjAQBgNVBAMMCTE5Mi4wLjIuMTCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANWs1uUL71nHYF9Zj6p+M3MpYDvx
+32iCjVdtH5a2qpSWHXTg0rR8dLX0y92cvOYvMXHRajZT1avpHr8dooPYSVaXpGMK
+NvF/Qi+WFYovRbP2vmd1yv1cgW/FggbwJFWVobizIz4seyA4d0B2j9fqoi2OFBNP
+huW664SjF0u3p21tDy+43i2LNUMAKf6dnRR5Vqenath87LEU41tSLudu6NXgbFMk
+jvfNkl4d0w7YCzeXmklmSI+uaX3PlJJ4NzQO2j8w5BvnKVhNVD0KjgrXZ6nB/8F7
+Pg3XY+d7rJlwRgXemU6resWQDJ7+UaC9u7I4EIP+9lzCR/nNBqUktpHRmHUCAwEA
+ATANBgkqhkiG9w0BAQsFAAOCAQEAos1JncV8Yf4UaKl6h1GdYtcVtzFyJvBEnhRD
+07ldL+TYnfZiX8wK2ssBtM3cg/C78y5bzdUa5XGS83ZKQJFFdhE7PSnrvyNqyIqY
+ZgNBxto3gyvir+EjO1u9BAB0NP3r3gYoHRDZS1xOPPzt4WgjuUgTLM9k82GsqAbO
+UrOTOdRnkIqC5xLpa05EnRyJPRsR1w1PRJC2XXKnHIuFjMb4v7UuPwyCcX1P5ioc
+rQszQcORy/L+k0ezCkyweORg68htjYbBHuwOuiGfok6yKKDMzrTvD3lIslls6eX7
+4sI3XWqzkPmG9Vsxm9Vu9/Ma+PRO76VyCoIwBd+Ufg5vNXhMmw==
+-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-ip-cn-only.key b/src/test/ssl/ssl/server-ip-cn-only.key
new file mode 100644
index 0000000..1966530
--- /dev/null
+++ b/src/test/ssl/ssl/server-ip-cn-only.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEA1azW5QvvWcdgX1mPqn4zcylgO/HfaIKNV20flraqlJYddODS
+tHx0tfTL3Zy85i8xcdFqNlPVq+kevx2ig9hJVpekYwo28X9CL5YVii9Fs/a+Z3XK
+/VyBb8WCBvAkVZWhuLMjPix7IDh3QHaP1+qiLY4UE0+G5brrhKMXS7enbW0PL7je
+LYs1QwAp/p2dFHlWp6dq2HzssRTjW1Iu527o1eBsUySO982SXh3TDtgLN5eaSWZI
+j65pfc+Ukng3NA7aPzDkG+cpWE1UPQqOCtdnqcH/wXs+Dddj53usmXBGBd6ZTqt6
+xZAMnv5RoL27sjgQg/72XMJH+c0GpSS2kdGYdQIDAQABAoIBAQDNXviU4WnF8rmQ
+K7bH+dBdqbETLKC8BG7xTrMD2sINWlMpmUUrsEtE7+paMGHnJAj0CoF5gg5m0wN4
+UXV4H5QtpEad4p14dAYbUreVP2ZRWKEdM7xM1HKcCUu2e22QzObJbXQ8N+iHyX3k
++Y+7yYrjGiH1hYR0nbnsnAyx++zyYBSQeqzpdQwf/BLY5xZmyYWNfqbckiMpEqMs
+EmZmGXnCjIipzEC0LQHoSW9PNa92Z9bvuxOKYl8iHYDDXjvMRFoZBSiMXpzHQocb
+QlQ5F4ayfW2OrOhpNbY7niYM9GN3Bk9TgMP+0BkJE6uuktLYW35LY1M78CCPWcWb
+npJNK3QBAoGBAOxkGrhAHAysSmtirIyMdvySb76wb/Ukfi+AULKz20FI5j4/GXm9
+qCb2GeT+FFSUHeSC8f0EFnosRYkdBGruqeZioI+5rUkboYFJPspAHAuvg9kgtfF+
+kvphD4O4P/foYsEZRx66FHozDbhrrR5UXc7KzqRIASc/D3FOx2UFJLb1AoGBAOdm
+WcaMvYygl9ZW+ThWAR1xG1X70AGKwrlrpF2hBkWYxSurxSMXnD0DUzC9Nb4EyCaM
+c2uSqEZOKdW+XfXtK2DnqXKfb3YCVEoGN4gVfyuW/vxii/+ZxLo3md/b3vrkZEVp
+pfkXy/HoZ71YN7bNpcDpOnhml6vvuCRCYFnI1WuBAoGAC0shB6pwbJ6Sk5zMN47C
+ZICufAK75o9OxAAyWsdC81SDQ3gKRImuDeZ2CD2nRP8qim9DFl5qoH2a+Nj9DArI
+7SvLFfK9958tURrpuAnmDRzehLIOXzI33WRjtFxKGhLtHOKTRkGHlur3fdcPF0La
+lHWV971E6NYXa8diuU3Mmj0CgYBYd+ka3/QYL83dRKNDxp3mg7fPx9ZewI5yFZVh
+to6PTTkU2Tclk4FIUl0b5TsGyw06r7fxCMENIBUegwmpXGOZSPifuhUDKSDQrE/O
+12knYTNbitG7hy6Pg3JxA77cbTVo1FuAQHjYo+IFohSq7zTP7FtObOrP8XaVZksw
+CHiQAQKBgBW4EiA9AAnZ1LOpifAvM7bs0NHg95qTwtAL52WKom2ga2H+lMhxeu6Y
+hUSytC/f9kALVcYloZhkLYpO07x1gXmy7f4parMjA4Ex+4vfu3kPd8GiNGZ+AUJD
+nnJ1OINY9ziXJZfju7FpVWpkiuPzWCh6y/o3gZ/veq5mIUxuDMVa
+-----END RSA PRIVATE KEY-----
diff --git a/src/test/ssl/ssl/server-ip-in-dnsname.crt b/src/test/ssl/ssl/server-ip-in-dnsname.crt
new file mode 100644
index 0000000..78ad8d9
--- /dev/null
+++ b/src/test/ssl/ssl/server-ip-in-dnsname.crt
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC/DCCAeSgAwIBAgIIICIDFRVYUgAwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
+Aww3VGVzdCBDQSBmb3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHNl
+cnZlciBjZXJ0czAeFw0yMjAzMTUyMjU4NTJaFw00OTA3MzEyMjU4NTJaMCAxHjAc
+BgNVBAsMFVBvc3RncmVTUUwgdGVzdCBzdWl0ZTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBAMpn5bP1/OfBQR/yvOkOBzxArE1j1YShVa2pcj896+CVDEgV
+N5Hluz7KHU/JYzNZCAHb5WAHuvXxKeoj4Ti5be1KsqO0mN1p+RMN7VlCpCpb0AWT
+z4z+I8TUhSZnmgghHvfW4RfcZMCcHq1vevVTDxR/cAbDPYpgBCD5F/SZMRyMDw5B
+7ILLmft0eqA1nCqavyqBCGZvx1ol8N5BfVdrDXp/rN5997khBWQRZ8g84FZyFZXf
+pwp57eu0OGQDzZFXoEL2t4OVld67K5jcclWVxHY6FGcHjCvyqs48PCPOR84anZwj
+GsqVOS6250/DWKBQO4KyhkTVf0AW/ICGSMOKkAkCAwEAAaMYMBYwFAYDVR0RBA0w
+C4IJMTkyLjAuMi4xMA0GCSqGSIb3DQEBCwUAA4IBAQDIAAH0WJKEpbPN0QihN6SF
+UA5WL4ixsBACo9OIAGkSnKeOeVEG5vvgOna0hjQcOcgtI1oCDLhULcjCuwxiIW6y
+QntOazyo0sooJr0hEm2WfipvIpQs6W9E1OTcs624BAVfkAwr6WT2VwoIAPcQD2nR
+tIQhSUIR9J7Q5WbzuQw7pthQhBfW/UPWw7vajel0r1dflbe0Cgp5WGNfp1kYy+Qf
+XW/YjkstZEP1KFm+TF58uxrIDmYboS8EerUREGQixijbI0AfXjShxtiyS63rbdpo
+3C0BPj9Yx2VtWi4U0qoef/iLJxJBCLvE/97+duPdKx0AkkOWA9VuenkWLp797UM8
+-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-ip-in-dnsname.key b/src/test/ssl/ssl/server-ip-in-dnsname.key
new file mode 100644
index 0000000..ba319b0
--- /dev/null
+++ b/src/test/ssl/ssl/server-ip-in-dnsname.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAymfls/X858FBH/K86Q4HPECsTWPVhKFVralyPz3r4JUMSBU3
+keW7PsodT8ljM1kIAdvlYAe69fEp6iPhOLlt7Uqyo7SY3Wn5Ew3tWUKkKlvQBZPP
+jP4jxNSFJmeaCCEe99bhF9xkwJwerW969VMPFH9wBsM9imAEIPkX9JkxHIwPDkHs
+gsuZ+3R6oDWcKpq/KoEIZm/HWiXw3kF9V2sNen+s3n33uSEFZBFnyDzgVnIVld+n
+Cnnt67Q4ZAPNkVegQva3g5WV3rsrmNxyVZXEdjoUZweMK/Kqzjw8I85HzhqdnCMa
+ypU5LrbnT8NYoFA7grKGRNV/QBb8gIZIw4qQCQIDAQABAoIBAA2kPP4JCTeRddMy
+Z/sJIAG2liZNITnkKcMflXyfrsMfKIm/LFSf+CO+OYWEHDR8vqZpbKcxPi+PRnTq
+YCaTkM4aZ7nS1S6vEsNu/90xOaFFONr3YFivVDfS3vp8pwv/N3gaumcCSqQUoZis
+18urAmwuPp2mEQK/f+e9AhlRLdcvlqDyKm+zMrVixK77Hj5JiEkh3rfZ3onHHKGE
+B7T2XRRqnZ4FCN9qLH2pMGUknZ4MGC9SlCyoerXFodb4DhKWQhJDRLjb8qP96r/E
+FGSg5WUiAERU/OgODoqZNTeIwIDB/f9NK45dEY3Hw6BsSFfU2VChrlNoVlzFUx2k
+yaH5Y4ECgYEA8rht3crh3GTy0jBJjNqB2iul8fkG/uiaiSvERWT/+KZnmV1+JGAW
+h2/wvd5apagOJjqKY0bCHMei/qYF9r4yJnkIy4qNper3QUz7TMCjsWduCm8S834A
+Z+Vwi3RBGJiQQH9Dfexko5sDjo+w5g4RsH52INCeReInNdxHOv06jZECgYEA1XrR
+QNwZlxHt3H93YKmKDZXikqW12Cuq6RSwf5VVdeuzV+pUN+/JaSgEuYsBilW7Q5p2
+gPROi0l8/eUPsBJb+dh1BcGzSjI2Kkzf66QOTG83S7tCPwQhwJUAylFuADvURjPQ
+qvqNjbQUomdm2QjBzyWtiFbolqxBgM3dnE6R/vkCgYBYGqQexx83LhmKPGbmTwal
+mARzkg59BxfZRN7IxcG4k0a1v98i+xISdYqwkP7cdOU18Tf8k1mwsrKytrcheqaf
+mn2bzJ5gJKs9s+DgWmjQ45dpCCqb4hfpnro8lKVwdSifkNKB6gYZ8RHYdMYkq+S1
+6SGeBbv95/qNrXjZq8POUQKBgHyaDwD4dsdCY79LdvYofrenQHOv3Q+rjTo2JT6S
+fysww6EQ2M89WiXSgc96Xw/LMl4nDfv+nMmXvyjCRgHS9XRC7yrJAEjSPeM6s4fq
+XZ4nW/ML/YKiesDZN3jfRoFEaoX/QFBLpcuLzG9uQw1ymwy5RSxK7b7kE+eGQU82
+XOihAoGBAI3xvT9fG3jRsSuw/8OQBlmDUFZcT0fRPRZ3pg8XlSreAam4b607d2WY
+u/bBHIclG3CLJ2EFqBtxl9AQeM0OTweF0KmV3dbtdBmaTbnhbK8/NLYnl5+aosEJ
+YrFKD8k8z6z+mYQs+7bAnfRa53TjfC7f24BpgEQyEfKL2fa3PF+J
+-----END RSA PRIVATE KEY-----
diff --git a/src/test/ssl/ssl/server-multiple-alt-names.crt b/src/test/ssl/ssl/server-multiple-alt-names.crt
new file mode 100644
index 0000000..58799e4
--- /dev/null
+++ b/src/test/ssl/ssl/server-multiple-alt-names.crt
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDSzCCAjOgAwIBAgIIICEDAxQSBwMwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
+Aww3VGVzdCBDQSBmb3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHNl
+cnZlciBjZXJ0czAeFw0yMTAzMDMyMjEyMDdaFw00ODA3MTkyMjEyMDdaMCAxHjAc
+BgNVBAsMFVBvc3RncmVTUUwgdGVzdCBzdWl0ZTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBANdIkKX1X+Jwqo5EXC1z/TjUKnYTDzHYx2rCqprBU8fN0mSy
+lMyjDm+eo924PN7LahqCHeDCMbapwymkoNfpLHkNRwotHLvxN5RyxJD4m5fXclRo
+V1ZzwwXTqXlECwrzzYGst/7muDM9DX+0vXIAvQGbvxBGI0CBM3ztHBADXlSFrYGX
+zN/to9KZmeOgBGJRGSZJg09P5px5N2E49yOqkIa9+MGb6nK8KLmETeTYjlWCS6W+
+oD0qGpZvj2Fzioz+Pn1q9fB3WS687GuMT0WvV3LAzcn341r0E36bUf9rxSjfBX79
+11KsVMemr1QskSmvMQFEv6R1Rp8xUGPqKlkRJ9sCAwEAAaNnMGUwYwYDVR0RBFww
+WoIdZG5zMS5hbHQtbmFtZS5wZy1zc2x0ZXN0LnRlc3SCHWRuczIuYWx0LW5hbWUu
+cGctc3NsdGVzdC50ZXN0ghoqLndpbGRjYXJkLnBnLXNzbHRlc3QudGVzdDANBgkq
+hkiG9w0BAQsFAAOCAQEAuRAyYBwAZLKERoYDy/kE9LKddJfLhledTJ7+cIWs6T9V
+KBfWBHZYxfxmdBYwqVZfog8c5uHREfWiUPoF/aMq3ARay96aMh4xXJ+2a7HAmknF
+9AJWRieoc3H/QkMzAuT8IDTmoEarsr8vsX1MGabobZte/B9tEjq/z5t3GfLrHMVX
+5092U6Ka40ii4U1VwjR8YnRBwjm3UpLmZJAjvXjw13/XucNV5O8Plo1yvS+G0AMh
+KdMxExiItVtjZteiA0pJf0YGAzTFyzvwBljTcs4NfZ2M0ta9i0r4BF7wQ8tDezN7
+VxdJVPc5xPqncp0cMdUAE2xDmYlKEqB0kuAHNwH5/Q==
+-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-multiple-alt-names.key b/src/test/ssl/ssl/server-multiple-alt-names.key
new file mode 100644
index 0000000..57f3114
--- /dev/null
+++ b/src/test/ssl/ssl/server-multiple-alt-names.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEA10iQpfVf4nCqjkRcLXP9ONQqdhMPMdjHasKqmsFTx83SZLKU
+zKMOb56j3bg83stqGoId4MIxtqnDKaSg1+kseQ1HCi0cu/E3lHLEkPibl9dyVGhX
+VnPDBdOpeUQLCvPNgay3/ua4Mz0Nf7S9cgC9AZu/EEYjQIEzfO0cEANeVIWtgZfM
+3+2j0pmZ46AEYlEZJkmDT0/mnHk3YTj3I6qQhr34wZvqcrwouYRN5NiOVYJLpb6g
+PSoalm+PYXOKjP4+fWr18HdZLrzsa4xPRa9XcsDNyffjWvQTfptR/2vFKN8Ffv3X
+UqxUx6avVCyRKa8xAUS/pHVGnzFQY+oqWREn2wIDAQABAoIBACtGhP03Y/zq1P4g
+M79XT5G65IYzspw8jWmilBTjw+moMCDZ3Rt9s4swgpQxUtseXMfTXBowLzoeygJ2
++3YrgysaRit/ggUtqhSHNYhG0VAmmO7qwpO4VX24XJrp2KZs9+SXSa1Nx71VCn+f
+X22pRFUsb63fy3pN/oGgUEHPy4iFsDm5K62lszzzwXmcWam30dcK2Ddw07FAwpSR
+2hW0veXpbZs33CX0p0js2imlSBwMLPbYIXriRT8Wpkkp+LvSy7/vDK3hWGhrKflT
+hXZsHINEBwGwfEP7uSgTUiTlm96Fwp8SXLC0A7NJL8uJ2ARxuDqniq0UbqTpvGgY
+RlgkZVECgYEA8rPoMuhJYHkejfh05qqycs3RYAdMIeOZ0wGzbELR+nI0FoAITHOB
+KsdMUaNrjICMKAJBNx7cl4Qb5IP35dcZSyR9pr6W6QDCwnRDYxGSCakn3gEtLgix
+5rcrf7r8QUyDUjCjasAZoql3rlew6q4HtSfBKciNuQ1wYnuaf5QdQAUCgYEA4xQU
+xvTbAYAhpmrDhIMprStBtAHEM/1N2RiV7jlw3WI939WBSRTwqLmDSJNc4he5m43w
+Dew2HPLFW6m/2jsXhYCXkACsgn1E2o5wPPcHIgnKe8eO26HuSIg75OsDaxAOGtMi
+RQbXelxtXDnRbsjiChYRucH13EhU0lsaffNXrl8CgYBEU2WhP0e5AyAY88NlVNTc
+ARlaoXNLbxnVD3uFlOIsUY5cbzrm2vWYJ3dS3GDgsyfB87CMZgHQHf8EPCrD5+RV
+BTbihHFTs0UhHT4DW+TzF04D7+zaMtRykUqLsQZnE7U8pDi9SstswazRxhomV0wQ
+Mdrtemp7mE71SrraA8agSQKBgQDSfC62LQlEXszSQWxyTFI5XjtM68Y+mrGqZouz
+gjMIQqQv8uwgHfTlsO/sOgyC1pMJiYvWm/mc47vkt3hKhTPMX+IdbUJ6wjssi5Om
+LyTBfGngSp41H+iL+xvpmZ5Vg1BPtR2y9iCOH1aPgliLZFGCH+rWUN/hDHrzcdcg
+oIvJ6QKBgQCnYc+oZqcdisoSYPg7IZSWsPz3mWsFtR0Xw54zQ0n+gMjEzSDjO57+
+8nMUpXwnspo/x8qbsrZ39YeZZvwXVTXlpQjywOOGkIua84+EQUnknK+osKBQN62m
+PWfPxXCTkWSBf8V6KKG/LFS6bZZu96h7+uWHkEwcD+bACS+2vGuyLw==
+-----END RSA PRIVATE KEY-----
diff --git a/src/test/ssl/ssl/server-no-names.crt b/src/test/ssl/ssl/server-no-names.crt
new file mode 100644
index 0000000..b5d0589
--- /dev/null
+++ b/src/test/ssl/ssl/server-no-names.crt
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC3TCCAcUCCCAhAwMUEgcEMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
+c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBzZXJ2ZXIg
+Y2VydHMwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjAgMR4wHAYDVQQL
+DBVQb3N0Z3JlU1FMIHRlc3Qgc3VpdGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQCfOf74edog2QHkJlreO6NJEe1VZUSxn+LBeHH8T5fniFiM4Ym9X2o3
+XKhYsvNSwvrfWwMkajMkd3b3vURiuiAxYzB/9AwX97RUkZ8TfuU3UgISiCbJZrVH
+TpfJEv7JhePgYpAoOdPWqtFPmnO/Xv6uNjsrx/V/3COovUj3eIcyQzAl+eC2U9Tn
+//dJ0kF+hDnOR3I/3e6bAboJjAVvLl2ABryaateHuUaCu/Bf5mG1DarXNXPKYuP+
+KrkjHhH0KQ4Js3nu7bPEiG0E/JmCR452j72WKb+PiJHOxdMMyztZ3k6bGGlbw60j
+CwQnUJAlPL4G9U+lpVYG6f7HxOaJEscfAgMBAAEwDQYJKoZIhvcNAQELBQADggEB
+AJAwYwIL4oj3NisXCXkEp9zqDXiZvNW9yW3bY8lFFCpU7o5n92tCf2OFAkKaYhF1
+Eb2weyDULtW7W/wgdlOZL9npayYKzTusl6e8xfTQyjRCsoKWvnWOEkPH7VraZJ8c
+Ko1KhaVWX98VLdlUh5giYAEkdhk0qPYKsQ32unBXXJu0pX63pnPDoaUBiZUWr/3l
+CfkjgGY5YA8YxiDlHGNF1qlcX2fQKloDlvtH0L5Enwt25w2/IvWhTN6YxDR+rgdD
+XYbQr6o6vsmnZTJ3zUZ6XFo98sZq5L9oy1pcC8roV7w0AUVxraTWYILyGfNgruG8
+xsok/hu1L2VnktveEW/qoVs=
+-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-no-names.key b/src/test/ssl/ssl/server-no-names.key
new file mode 100644
index 0000000..2edea5c
--- /dev/null
+++ b/src/test/ssl/ssl/server-no-names.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAnzn++HnaINkB5CZa3jujSRHtVWVEsZ/iwXhx/E+X54hYjOGJ
+vV9qN1yoWLLzUsL631sDJGozJHd2971EYrogMWMwf/QMF/e0VJGfE37lN1ICEogm
+yWa1R06XyRL+yYXj4GKQKDnT1qrRT5pzv17+rjY7K8f1f9wjqL1I93iHMkMwJfng
+tlPU5//3SdJBfoQ5zkdyP93umwG6CYwFby5dgAa8mmrXh7lGgrvwX+ZhtQ2q1zVz
+ymLj/iq5Ix4R9CkOCbN57u2zxIhtBPyZgkeOdo+9lim/j4iRzsXTDMs7Wd5Omxhp
+W8OtIwsEJ1CQJTy+BvVPpaVWBun+x8TmiRLHHwIDAQABAoIBAAtkaeK7TSkGfcUm
+HWBDIharSrDOcxDGYMH47SbhRvwQ3E0QIfvDpOTbI0xdWV11h9+NMndbhdc5GPD2
+wLrTmFQQRbsR6f+ZAHUAikIp1RqVKoLK7QOB7rxwWhnP2xzuEHTQeIH4STjVte4d
+HeT2VgB+7tLeFqmURZTgHiVeoUWuPgl2/L7ABK8x7wk6/Ho/FyB6bQsX9ixfd99W
+lxAhKr46Sa6ceMygswvqzxUcFm0lCSfMt+VTscZTqtQnqiV8mMiJk5novBUgpS95
+JaLsAKsG2mYKHBaAs+EbIbgk0hBWnGB6DFTd8/62u7fJFWA5BvMiNBnde47wLRJL
+BAHzw7ECgYEA1DVbs4lN/GA8ol+ERGGIhZUa44jLgIFrE7kpYdKoi8AF8R8BaIjp
+xlI6z+sxLcp7Z/jccRToGH20OX1i+x4Vt8NGvzkEOdowX+BwMl92v7vSrr6PGdWg
+X5Nu6/ISVarIDWBSLGmdfqJ/szu+HRBh4CvFlrf+379COkZ9oc9Hh0kCgYEAwBWv
+6J4oi4nbxyzpDpI5YH8wu56A6uNJAD5z3pca7XaR6mOLiJhqhCQscthx901dV2fT
+tECOxX6/DEvI1LZejiyG0Y9LXfhH37ZpEsgY14SNC4SJOW3dzVld2JEcd/3+50A1
+86DXImZoWeZzbiavkAxecZFZ8zoTUifYeh9M0ycCgYAQHZE+PDIo9WIFbr2Lt+B3
+TJCDMRNLSgjIsaob3LSiEE4jNpiTyLoALqR6v8C3WoYuqi6Lg+vwWDOEnioTKgC6
+OOE5imnwvsonrdK3cJqDCw9/58bUTm3kdDzbPEH6MYMJyQPUjZzBTjPmd6YDbQgR
+zyEtRgHcGhk8dbf6vtQOyQKBgQCg0geDhNeBbJybt9gwoPB1AEh27RAWmNDH6YHt
+fSnIYxtr2Ig8hw+3LuogBWP1n8pkocM4CUz/wUyHKPQuU7n64wDFd2msdXEHtptm
+ZC2YU5wbZo3VjUzE3uuZpHTnabr/Nl11atZ0MLVxf2ZpdO5Mdm6kOwPKhncis8Wl
+CYuyxQKBgHPgMjy4OgNclXfZHkk8MrHYJrZsX4NYKCAQC9z5pkHP3Osakt5YPdPq
+Hti6rFMzagHlYY7k8tMx9F3j/kQZrBq4yfQIWsnx+OIr1A/A/0jbmTHMMqlQ8EBN
+p7nfoCzlvm0lHQV2nUb/9UfP/Wc5zDZZnnBm83zOTjBTBZ55twu6
+-----END RSA PRIVATE KEY-----
diff --git a/src/test/ssl/ssl/server-password.key b/src/test/ssl/ssl/server-password.key
new file mode 100644
index 0000000..a8e383a
--- /dev/null
+++ b/src/test/ssl/ssl/server-password.key
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-CBC,B335CBE53A05F4FC5805FC038BA80BA0
+
+1U4+GwI8FGpcrk+9uzMlQU5UZ9xOJMOZb9xA3IYMw+2BLF7zVbAkYyyiqF2pKUmi
+doOYFOGIXNV1VhVwlw674SMN+PIg72b2F7DDrqEYlicLCU4o7eeGhoiIKzTksRTU
+YV3nYCCDZCEw7V+pFeGCUAc9fc+Y0BGMYIshLVdlTYgVjZScL5kHuD9t8xa6AaTS
+mQp3jInRnHjEJbRSZnFQ9CR1LUtmGE02TOcWzoGshFdwCdtO/lJzBmmMxoL/qV1R
+Cqc0PKSANsbgvTJMriZXYSFjpMYXmxBQXDYNuFfwq67bssAVIpTSvWu9SfcY/JwV
+OqERcb1zPgDmprDvd/L7Vh/cdEWWWewOVoUo89cT7CrLvMINHqE6smM2x1xv91BB
+AOpyoGJliPGAcLDVJINm9zC1ErEjSEcR/VumZKsgSTsBYgyYezTPQYAfe+h820rs
+eC4GMu+zr31U2TVLYcb4j2t19fTgaQBj/LH3OBse9+0quoJhzmDjKelS3O3BaF05
+DM20tJRHANM+1WQ9+aFinXa1ozcGsrLSUa99oFqL4vKgL7jd0+wmCzwxaSp3rHB3
+AFHCdUOayDAdPhnGwathhAZ0AjyEJyWnA47pEpWDr7SytpbiMwOoPcW8/oKid10e
+qBK7uGK1Zc7rtckjK3CrM1VFDbxzwGbF2aKHtFFyrJtUvJwfP0Y1V2DncOsiy5Nx
+gJ3vxfi11gxnhd9VmcoY3JVvTHOsw48xYNFrZXve/X3o9eUDqb9VRs/vV3t5w+xR
+RaUPdz9cdlp2AA4xW/IvIQ7XwuBWPaPVr/g9pUvI9iJ9Z4RdruvjqDAD+ICVx9MM
+8SuN7X3gmg4mF5FEL0ct5ZdP16U8/EYvl7Np7vN3kYqbqucwCJH15R8LckAfbzIH
+yYTXC1iik4GfyN9tTpQtZsZCvV2Uo+Fo3mxP/EzB6tNbfOi3LG/coverSwgZLQsA
+Q6+Kta4PT671xXdaGLT9tEMIai9SiW5acqcdhjYvcaP69J8ZtKpNpP6HTL7IZD8p
+SbMxE9jw+bYXILR3Ie0x98z4Z04Q28/bPbvPTbXK8nv6/YpjKgq4hrRG58psHdbX
+ggS3RNzcJJMDArBka+zvbWL4jfWZhllMyGqc7q/FuoEqC5JlMTUBpru3NTNp6ZgQ
+QXRV1Pc02ff8Dp1H8FP7B7bG3E2D9eTUqR60WvmGnuAqvXgA0+4rEaUKfxELH5qc
+dZgu/yiuMttCha835wMLnOxsOJmHILwrc6/uQWydx3vNEWFx0tbV3FzVBIvqdpME
+LA4iAAz5xqvLgA5ii23Hn18ycZGU7gTERK8RdiALRzPtBW6hPreQjiMTJnBaMhXA
+Xq9opGsNmH/rZgXuk2VZ79bbl9pKN+z9ssRGzbHCVlEckfaxlrYfANwzk8PbOrZJ
+6UW3Gf2PwRRNtiVEabf0upVng7V70KSRzjfC7KBHYwbRIL4nObgTG+vc1SjgNgrx
+Ue/e8h9qiDBmgdH0Uvqfqb19HF+QzmUNoP9TVQFj+4+DuW5zN0D8weF4TuBgyHr6
+Y+Rbmq0WJlIlc8KMwX87nACesmFNSJkI0ftSLDHrLuvXRtB8f7s2cw3hd81i+scE
+-----END RSA PRIVATE KEY-----
diff --git a/src/test/ssl/ssl/server-revoked.crt b/src/test/ssl/ssl/server-revoked.crt
new file mode 100644
index 0000000..3bb0f16
--- /dev/null
+++ b/src/test/ssl/ssl/server-revoked.crt
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDAzCCAesCCCAhAwMUEgcFMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
+c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBzZXJ2ZXIg
+Y2VydHMwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjBGMR4wHAYDVQQL
+DBVQb3N0Z3JlU1FMIHRlc3Qgc3VpdGUxJDAiBgNVBAMMG2NvbW1vbi1uYW1lLnBn
+LXNzbHRlc3QudGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKKD
+zvJUs+N+KeDwWAW0zfI5C1t3BxKUwh+MrwtFeNIcxhJd9Bzy6fNnvpMa/kNPoHfN
+n73OGLYeSDyiDc56dvBjLOfxPXFFN4TCuIxYSizIjniL3tzP/a8hyvO+KqTYyaEs
+cT8+/rNnqlqBXNqcdChSGpk0y34uybvWj2/wDJWTbFJ20bI+30HOxCfK8Dp3s8Nl
+suVSuLKF/qqbidDZuOAKc0/GJo2F/5AF9MkMYELmG6XAVq/XDkI3oLtxQKh6kYfc
+nu3fI0Mwr9+FoP2q+K5KskA3KJLlgBOykG55Odbe6Js4TPHrMBTgC9aWrP/I1gb8
+tFY2FVN+D/Wl8T/Boh0CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAxVHoqX25W4Hx
+pMNjv2AJzcB7D+c+dUXAmLLJ7jh6szWeL0M2E5qX4dLc8LzQKnXv5ZcT4i/akjDX
+etdzuqh03kvDJvUkHclSWffmowmWMTG6GCA6S/2TQzSibIptkwqs74aIkayVJaC4
+jCBR+PVT8+cE2FMD6dAWu//fyEcpTg6XpZ/Upgu9OITGNaEQUGz8pSRkTgspfO0Q
+AKPmql6dpywReIlr5mzy9liCzf/BbAVHGmP/pBGIkLn2AzvPLCQ/UFZYT6aH7l5J
+nzmFhgRC3U5wPMdelHGrPMXg6OHCcyrQY0kEi7N/GQ5+jZkICoQuPJ7APKEZAUgO
+XRwVulaWJQ==
+-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-revoked.key b/src/test/ssl/ssl/server-revoked.key
new file mode 100644
index 0000000..1787754
--- /dev/null
+++ b/src/test/ssl/ssl/server-revoked.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAooPO8lSz434p4PBYBbTN8jkLW3cHEpTCH4yvC0V40hzGEl30
+HPLp82e+kxr+Q0+gd82fvc4Yth5IPKINznp28GMs5/E9cUU3hMK4jFhKLMiOeIve
+3M/9ryHK874qpNjJoSxxPz7+s2eqWoFc2px0KFIamTTLfi7Ju9aPb/AMlZNsUnbR
+sj7fQc7EJ8rwOnezw2Wy5VK4soX+qpuJ0Nm44ApzT8YmjYX/kAX0yQxgQuYbpcBW
+r9cOQjegu3FAqHqRh9ye7d8jQzCv34Wg/ar4rkqyQDcokuWAE7KQbnk51t7omzhM
+8eswFOAL1pas/8jWBvy0VjYVU34P9aXxP8GiHQIDAQABAoIBABp1d0YBAGCzc8IJ
+n2seasFbBDxZ/q7JxWk5kG43W1pqEN2AqnPkIK7eXyq4JFl1J10Z/z35xhAwkfY9
+NB4/1gmBPBhvMF+2szlMMpu27CyqYnfB3gD5ZAYVbGOOvIamPP2erLltWi5/XD7r
+/OAixM6jv2zeKZtbpsCMSEIjRQk8+t4LXdT1ohrhm649QxmMpnYNjpXJ9U9uG0yP
+lr2+Lk2Xjv025kP765iGP3U5fW0/sONxXVM7uUyrvtnMJPhsKOdsNO84ratOVcnM
+BgzSEB0nldTcg7MUQyA+oOfDOXgoTQ5WZuXrx32sEDwN2ceCBg/qreaDwkC+KI7n
+nWazf0ECgYEA0ebcOCWwZlwvM/FNgC7Uqbxn6kjAkNvcETWxiwSaEf6MsTyytCJv
+RaVE7w5FsKKWxdu7ljft5LClNXTbscV5O5HuDMrLNSJFuhTm2dzYECZaUmXgN5gg
+JQAhhxevk3UBkGB/EYEDEBNtGjGWdWn0kFIsY4oN5l946cA27WXmsSUCgYEAxjTA
+XfGgM3+Q6hepN0J9XuVaebEkuTMlFmt82J4pMZxlam9zJDrDbzGVZ4kjCqLTh89v
+Tt+hE3xu+Df5D4Vb/uC+bu4EBpnvlqJRPNz4aQFxt+UILznS+oS4mLV1gK5PbIMA
+gh1+F58XJp3+NKxvUnjERpiUzZRgSh+9gtwWx5kCgYB3cfYzhU8CkMbTuicuIHgo
+NuyzZ78dL9/lczabM30xbDdHzJCs7UOA0HGP0AFcaMl/wnDXJPCdSOBasSsr2IIK
+ohpi8Sv+Coi/QZG0vHW/ivOvHAYh3NG9/HsX0yS4tsazEBZ/MXk6trNJSpqiKi9f
+yUM1SaRrSj0WV6lqIqjKeQKBgDw27nIb4/WBPb9AbPISyw+3UeNCg8uX1B6ZjRYq
+Bo3B27WYIjzRdWokgCUyLmkeynCp/kDSA5dt6DCUoJ+sfiRSlsgQmzx+K6Fxsohx
+AS61d5zMgc4HHSdqhsIt7oKncg2fRtpAp3v5owjiWsYZ1MATXF2uIRbLiu0581L8
+FheRAoGBANFH5W0DtT9kyzdiPddfBMFnrsUYYIPgejAao7PvCCW5tX8CVDcRkLhf
+tC9zZgA9WEm1irXZtbo9m3LYzH3yED8DvBcsfCdA20R/Ed/om2OiLKD7DDFl1W+C
+2NrwzcQlRlhHC8V2D8yRU+6YQ4Eu9dYzFnkGeCGSbiqaa9ZkPYx8
+-----END RSA PRIVATE KEY-----
diff --git a/src/test/ssl/ssl/server-rsapss.crt b/src/test/ssl/ssl/server-rsapss.crt
new file mode 100644
index 0000000..1c35956
--- /dev/null
+++ b/src/test/ssl/ssl/server-rsapss.crt
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDezCCAi4CFCrZutHsw0Vl3OCgOmvtL0I/XAZyMEIGCSqGSIb3DQEBCjA1oA8w
+DQYJYIZIAWUDBAIBBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZIAWUDBAIBBQCiBAIC
+AN4wRjEkMCIGA1UEAwwbY29tbW9uLW5hbWUucGctc3NsdGVzdC50ZXN0MR4wHAYD
+VQQLDBVQb3N0Z3JlU1FMIHRlc3Qgc3VpdGUwHhcNMjMwMjEzMDEyMjA2WhcNMjMw
+MzE1MDEyMjA2WjBGMSQwIgYDVQQDDBtjb21tb24tbmFtZS5wZy1zc2x0ZXN0LnRl
+c3QxHjAcBgNVBAsMFVBvc3RncmVTUUwgdGVzdCBzdWl0ZTCCASAwCwYJKoZIhvcN
+AQEKA4IBDwAwggEKAoIBAQC6YtrZZukJ4n31gKpcIOl65D9roe2jzcIBX1AZq1fR
+I6qmt7aR0iFCKEy9D2fs6lM+NVQSurg7b0gKL+XoOadySAxALIrUwcCQM7rZvUR0
+aKo3Qm0U00ir4x0i73/sTpY25zBSFoqGldmlqiIIWxpe8hqZEc6Sc78Bs2FaAa9A
+5sTLaX5nG6jyreJweLcmv+TYFVqxNq7Y7tC67zWXr6r49JBkSHSibzBr/uFxOGsP
+B9hwGo4/foACjeDNAT0vjwMLnV19Sd2zf9daBo+sd9bCj2C5CpOyXxFtO7cMh0tP
+U3ZqcYPViFxcPObmhnJgqlBbgZD/WLxm1aFgUYjqMQ47AgMBAAEwQgYJKoZIhvcN
+AQEKMDWgDzANBglghkgBZQMEAgEFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQME
+AgEFAKIEAgIA3gOCAQEAQpYu7fz9iz8CplCOp4SJ1eO9UjbtdxzvuaVR751TfYrX
+OO19jq7YyWgqJDwROnDJBFEy9B+HaXTfscEHpGIHAIpx7S7az/gLnO90HshXcK+/
+CbjW9axRB9TrD2zOrISl9NSuEZ5tbd5/Ml2yzY85CCjYPuNy+euH5XgcXcwF3Q49
+G5eDJnaCCYzwdEOZY8ris9o9go8aL6zNAfhUKToRUfeoBCStOLZSgb6d/IKRB9eg
+M0FImsMI3j5zHCiH0HhMwCRFRuZqTp1EMBHANIJncTZSGWQyKQ71zO/l/3YzwNfm
+c2gyeh0DJWFkEZD3spWs8K6UEoTESP6Ivj47LmnWjg==
+-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-rsapss.key b/src/test/ssl/ssl/server-rsapss.key
new file mode 100644
index 0000000..a5bc297
--- /dev/null
+++ b/src/test/ssl/ssl/server-rsapss.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADALBgkqhkiG9w0BAQoEggSpMIIEpQIBAAKCAQEAumLa2WbpCeJ99YCq
+XCDpeuQ/a6Hto83CAV9QGatX0SOqpre2kdIhQihMvQ9n7OpTPjVUErq4O29ICi/l
+6DmnckgMQCyK1MHAkDO62b1EdGiqN0JtFNNIq+MdIu9/7E6WNucwUhaKhpXZpaoi
+CFsaXvIamRHOknO/AbNhWgGvQObEy2l+Zxuo8q3icHi3Jr/k2BVasTau2O7Quu81
+l6+q+PSQZEh0om8wa/7hcThrDwfYcBqOP36AAo3gzQE9L48DC51dfUnds3/XWgaP
+rHfWwo9guQqTsl8RbTu3DIdLT1N2anGD1YhcXDzm5oZyYKpQW4GQ/1i8ZtWhYFGI
+6jEOOwIDAQABAoIBAAPXZpi55PdieTXUQpxPxDJpx01p4IdAKoRzS3EwkP99d/sR
+qNCekaUyIW9UqT2Hx2Tb1MzCBUZQ40I1614fehK5C2sFdtnls8/gdaIe7FqwIYxA
+lcxhpvjHX2Ht8gLc8OvpC5vDOJkZymZsHM8qa8zcTD/AzzNBOpdHqwdES58YoqEb
+5LOVLBRIoLli2eAWrrnoYl7MQuh3CHHtWGjn3drTzg6Tl2umfNhTMFANZssNexl4
+6npPHBASdevWWsqB8GXD56PaqWxxnjtwzk06lRbloSQYJOicI8OK7eaySpRuHpZV
+3vJKhY3bcRN6joxveXA7jaAPSBvNXp2w5fQ1b2ECgYEA1mzqOCln87aaLzZ1KlWL
+QfxcXmcke1lJgbhW+iEh6iht2OmBlntAlIVv/D3yBDhNrHdrNlUcWvm+VSrbVyxn
+6e1RWHAGPzZNhpcg4odxdI6Oton/OBtsEQ7A6UJ6S7bPTVGVwi9fA4fI0Pfne0wV
+IeJHvjDZboOBi6TF2thcJ2sCgYEA3oYzAt4tEiA+nQyNnP4nWZ17XONA6H8yVeUY
+Sk6eczg8eGAQz9afVtbSI3uRIfQbQ1+mjaUl4pVej2UDXcROpYHgwCLJRBBDbzzB
+4IcPh2woFGZOScQu9Q64C8g6MH4zm3WkFvXyJF3j3dHGFZGq8nmwEARJgAsQ6Yig
+kYL8+HECgYEAtuKUbqxaPlL7dNNU4XOu3+v3eIkuY4qHGH36qUKDI62x6zVWUtvy
++/pHxnOrLRA8p6H/LosvMSUbwpZYGCUGyE2iePSrT1TokKfr42o0SX6hmG1g4iD5
+bh8QSKNrnZJhg4fXXJV8y40PqbQXmmENESZnnH8bpJfDcTBrlLm+99sCgYEA3F1f
+xPZLAglGmHZnA1K5m0iWc01l6RiVu3RNksC6r3XAhKD15S0wzGme3p6vAkXgfd8K
+bHlgxDuR0kWBiOkvzT2KWhvY3vuQHGe5w+VcnoqgQltyKiELM4mo/5oA7ib8anac
+0lQrwJHuZ6wnExMXjFqv3ZyxQQk0bWDtSkzCwjECgYEAusqqCAmryRFWdOif2z+Z
+3vfseSvBdQMj2FO7weqCVPV4Gnae0TO7A1bUpVX/pfkDEPitt5oUgS2KTozW5vwz
+yaQTSB8RO8EG66GURZvPs3Cerkyrgk/OMmbCv3B0ALwhPMBqpemJqeBOuyaAjY8W
+Tqb6E2ofRlYND0xH83gCTig=
+-----END PRIVATE KEY-----
diff --git a/src/test/ssl/ssl/server-single-alt-name.crt b/src/test/ssl/ssl/server-single-alt-name.crt
new file mode 100644
index 0000000..7affdd6
--- /dev/null
+++ b/src/test/ssl/ssl/server-single-alt-name.crt
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDEjCCAfqgAwIBAgIIICEDAxQSBwIwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
+Aww3VGVzdCBDQSBmb3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHNl
+cnZlciBjZXJ0czAeFw0yMTAzMDMyMjEyMDdaFw00ODA3MTkyMjEyMDdaMCAxHjAc
+BgNVBAsMFVBvc3RncmVTUUwgdGVzdCBzdWl0ZTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBAMWKHC1lrog7A8ye8C3NM38JBiQBMuIZR40wORl0hJxj5Tp8
+dX8Xo2Thi9Ry33+YfMwfkkF66ZRwnMMEa8VYBmOz+fZFzF19WpE8F1CR3PxKE7ai
+zvunxy8oMxdXdIuTTzt8a5NcDLe22C4Yj21qaZVoh182ycvMH93V4MwsLcV3/GdV
+Ko7QpwP2ZCf5D1rhyccx+Trwyb2bKvhW5Jd3GrRacFJQFfUyrAu/FvyuSPmn86ab
+Jkr7CCgFlg6e4O9SFY7yXiOgLotsoQ5/YriTLinvUTGCMCSxaol97qx3I2gUpCZu
+i7H+4Dt9L5FcCMshl0TU32dsjw6El1Wbzp6voCsCAwEAAaMuMCwwKgYDVR0RBCMw
+IYIfc2luZ2xlLmFsdC1uYW1lLnBnLXNzbHRlc3QudGVzdDANBgkqhkiG9w0BAQsF
+AAOCAQEAUIhBQLzQgd7wHlT9DARxcC7SZwQtnk2BVqMYTRBU4uIa0i2HVyetpe1P
+rREthYq5sgaSqdonD9Splg8BLUlah9y3v9j6DBxkxNnz/3AZuA5oPaC/TZ+lwlX3
+QNWWFNaNZdcQbvjUvoPXIbJ6U9UDfByOJdoN4kJ6xe8Faj1Mp5Euqzr1ErrMtPWJ
+XLnXLV4WyAx+iMAbofXNlCyUorPGA8lRudzQ7bKdrhMZDE66VYwlwsUejEiODt7M
+NGTDs4aAZz9cBRjMeXhvX60cFQoykjAvWbieUKOgaFmJJyKemFj12cLeWyxvUodI
+kYtgAdzftiCSrbDjl1pzPSM6RC/E/A==
+-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-single-alt-name.key b/src/test/ssl/ssl/server-single-alt-name.key
new file mode 100644
index 0000000..f719b0d
--- /dev/null
+++ b/src/test/ssl/ssl/server-single-alt-name.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAxYocLWWuiDsDzJ7wLc0zfwkGJAEy4hlHjTA5GXSEnGPlOnx1
+fxejZOGL1HLff5h8zB+SQXrplHCcwwRrxVgGY7P59kXMXX1akTwXUJHc/EoTtqLO
++6fHLygzF1d0i5NPO3xrk1wMt7bYLhiPbWpplWiHXzbJy8wf3dXgzCwtxXf8Z1Uq
+jtCnA/ZkJ/kPWuHJxzH5OvDJvZsq+Fbkl3catFpwUlAV9TKsC78W/K5I+afzppsm
+SvsIKAWWDp7g71IVjvJeI6Aui2yhDn9iuJMuKe9RMYIwJLFqiX3urHcjaBSkJm6L
+sf7gO30vkVwIyyGXRNTfZ2yPDoSXVZvOnq+gKwIDAQABAoIBAEtW0EZUKIuWjm1l
+FM8zGvfRVkE3H9PxtkNX5/8YXFdVFiEHRLyzJEMebnkZUrpUSwyC4gINQba2eGM8
+dWnvl4hBJQ1TM41YeMk5dN7qsrCaBAi88VozdBk9KLc3SKDPDwHuAw1RpxwOJUb3
+YQRm+FveYPrkZ3RNpr2xi6nzE4XjAH3LbF8EqBYC7LUm4GUxBl6Ke2rQiC8XwE0B
+0V0nvBvjkJ4tT4l9RTtInRr2vmqSWXp5bGVuuWqWxA/tBtTHhGbO+PG4i+C+u3NL
+qQgCbboqxyivPaMiMDdDhQL9TjAMCkItVxcwZlGdSA0+d5mraIXhs2ifF45soo4Y
+9vb4++kCgYEA6YpFAqYJnL0p5AIh14yxhWykLaE1YpKkw4P9SpxtGQIfwNDHyXme
+v/S66fLNvOjQyH6Y+gvGBGVHAwpM0RiPAHBADKAue6V9pbUITD0aQL9HOj9LEC+V
+8R2S5VSxNDpnMnd0DVdxiWGuNhzTG2McFXYduC3NpTLurK6ecPhVoI8CgYEA2ImC
+ZN2NS15AxWybddSgYYcL/44t9dfpEJ/4PJ1ISStIibHqpVWkq7vC4P7mMmS3DItr
+N3QDjBGltc1R4UfSCLakzSs5buC0LiO2uoMZFcOiZEd0r73iTLM8d9wOZRysYtHw
+T2tS1NvMrwK4TGZh+GWuUlSfuIbZ505PCQfYnKUCgYBdynoMpkIWAKJiP7j3qDlj
+LE6DRMr724jwPIHtBQWLlZ7LAQ47i+yFivPGIQ0fYSD4ZF9rjG7qNQJf5jMThpln
+w6z1ZR9F6SCc/Cdo9uEkP62LZv/ucC33t7jXATxpjUsEqZSiBwxB8EjW0py10wfk
+Vpt47Gw6fEn+b+KR3CoHYQKBgQDYKe4R41p6Ms1WSOWo62pv8fD4XWdkVPZFsmyN
+ljXjVWJEk2g7RRPunLIfClejVwelbkjKQvaHjdZvd1iWHKyAJlS+vLfJCGjW5rAz
+4UvZfkNO+EZ0aorPJt7miLeWGNm+jPXpUqqN9B6RV5XELzD+WAN+DRyliXlef75G
+tZ54QQKBgQCDXfap0mLGYXbFMLPF4Q1mnML5deVjyoGteAF+qky54rZvf0h2bWN2
+pi8hUOdwTtazgkd+rJp/a7eqQL/72nvCMonsb7vBNHmmNqZgaC9zyTV9AOE0Txc/
+vU6rvU+nQvt7esuTILS1O4SEeNI0JG22Dx01ebJQuKDcyOTOxv56vw==
+-----END RSA PRIVATE KEY-----
diff --git a/src/test/ssl/ssl/server.crl b/src/test/ssl/ssl/server.crl
new file mode 100644
index 0000000..331a83c
--- /dev/null
+++ b/src/test/ssl/ssl/server.crl
@@ -0,0 +1,11 @@
+-----BEGIN X509 CRL-----
+MIIBpTCBjjANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
+b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc2VydmVyIGNlcnRzFw0yMTAz
+MDMyMjEyMDdaFw00ODA3MTkyMjEyMDdaMBswGQIIICEDAxQSBwUXDTIxMDMwMzIy
+MTIwN1owDQYJKoZIhvcNAQELBQADggEBAJxj0taZYIIxUsCuXR5CN2OymjMvRwmV
++10VOkyBQ3VkzHlXeJkmZsU2Dvmc205l9OYouh/faL0TfK2NyhmBo+MrTizL9TBo
+4u2es/0oJGj2wyNMkRs0SlSJelakvGFBvSKfqoV0l2O1WDV7M4KtdC8ZVZipmL4R
+ac4hBMK0ifHuTS5Od6o0C2RijEPCHMXaS/LkWpBqcStI2oirhjo+Th1wxTMGUVFy
+imVvt6D6QqqHCUYrvcNEN0xBNFwJGq/0cgSy+w5szt/RRehmJKX8MbNeZxrznIIx
+B18ch9rbBltz+Y4R63rCN9MdsnGXf6PQ6a6doZhSI1pnDrui12MOQrU=
+-----END X509 CRL-----
diff --git a/src/test/ssl/ssl/server_ca.crt b/src/test/ssl/ssl/server_ca.crt
new file mode 100644
index 0000000..0d6d7a6
--- /dev/null
+++ b/src/test/ssl/ssl/server_ca.crt
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDFDCCAfygAwIBAgIIICEDAxQSBwAwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
+Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
+c3Qgc3VpdGUwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjBCMUAwPgYD
+VQQDDDdUZXN0IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qg
+c2VydmVyIGNlcnRzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4kp2
+GW5nPb6QrSrtbClfZeutyQnHrm4TMPBoNepFdIVxBX/04BguM5ImDRze/huOWA+z
+atJAQqt3R7dsDwnOnPKUKCOuHX6a1aj5L86HtVgaWTXrZFE5NtL9PIzXkWu13UW0
+UesHtbPVRv6a6fB7Npph6hHy7iPZb009A8/lTJnxSPC39u/K/sPqjrVZaAJF+wDs
+qCxCZTUtAUFvWFnR/TeXLWlFzBupS1djgI7PltbJqSn6SKTAgNZTxpRJbu9Icp6J
+/50ELwT++0n0KWVXNHrDNfI5Gaa+SxClAsPsei2jLKpgR6QFC3wn38Z9q9LjAVuC
++FWhoN1uhYeoricEXwIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB
+CwUAA4IBAQCdCA/EoXrustoV4jJGbkdXDuOUkBurwggSNBAqUBSDvCohRoD77Ecb
+QVuzPNxWKG+E4PwfUq2ha+2yPONEJ28ZgsbHq5qlJDMJ43wlcjn6wmmAJNeSpO8F
+0V9d2X/4wNZty9/zbwTnw26KChgDHumQ0WIbCoBtdqy8KDswYOvpgws6dqc021I7
+UrFo6vZek7VoApbJgkDL6qYADa6ApfW43ThH4sViFITeYt/kSHgmy2Udhs34jMM8
+xsFP/uYpRi1b1glenwSIKiHjD4/C9vnWQt5K3gRBvYukEj2Bw9VkNRpBVCi0cOoA
+OuwX3bwzNYNbZQv4K66oRpvuoEjCNeHg
+-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server_ca.key b/src/test/ssl/ssl/server_ca.key
new file mode 100644
index 0000000..0204dcf
--- /dev/null
+++ b/src/test/ssl/ssl/server_ca.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpQIBAAKCAQEA4kp2GW5nPb6QrSrtbClfZeutyQnHrm4TMPBoNepFdIVxBX/0
+4BguM5ImDRze/huOWA+zatJAQqt3R7dsDwnOnPKUKCOuHX6a1aj5L86HtVgaWTXr
+ZFE5NtL9PIzXkWu13UW0UesHtbPVRv6a6fB7Npph6hHy7iPZb009A8/lTJnxSPC3
+9u/K/sPqjrVZaAJF+wDsqCxCZTUtAUFvWFnR/TeXLWlFzBupS1djgI7PltbJqSn6
+SKTAgNZTxpRJbu9Icp6J/50ELwT++0n0KWVXNHrDNfI5Gaa+SxClAsPsei2jLKpg
+R6QFC3wn38Z9q9LjAVuC+FWhoN1uhYeoricEXwIDAQABAoIBAG/c2Ua3Eegu5PwF
+hXp7dUI/4BfKcuBiX7BIl2tXlOAF+xn56AZDTcuGirLeu8knvBUCJfI/Xy7V7lAQ
+dyVz9qQVMnIpOTAxXr8SGaStVt6pX9UL14IuuLbGVBLzmLi1YyCwDXSVV6lV7a97
+uv68N1yFsrNwDgP0ys6/gtL4mWRkouFBbfJS9gDQjgSYTjWUx4wSkMw8h939RPkS
+ccmdXJxwhDBTP8iJIhVVR0FK7fCQvsQCuchsvYPTu5VCExTfNhO5A8oGZncnQRPH
+/RAAdPW2kAZV2oKkz5RAIDTnVkhXv1wQLty9E2PgjE04Fexe4Q7PCGmbrh7nBp73
+ARVuTRECgYEA/U3gwte+2pRzEciuoB4b+8Sod9eBxQGLhcQWOx2o0PAL2FIVWKxO
+exUC/ipmEX0mEwnAvVKGO1MTsOj6LUZELgbnygscLEQc1bNauKuQu/ChVfBgJ9ng
+IQR6z2BhrsOflfU8n01oMOjfVlVzZMdI5Nwy09OQgzu8tA125TUSkPkCgYEA5LL8
+bh5iykAlgXy7pA6WZmZXV9kaSTdnGGZ6GS4sbFJ8ZVw+tWi+xTUL9DES4keQTga7
+uneWu7q8wP7zdHCnKRhhBnbKFz1Voh4Z2VNSW9OjJHS4+lZfd94JZavOdwVMOQK9
+9Zjn2nsZalGb77pP/zDQSHnptwJOAKV9K5X5bhcCgYEA3wCODNtlogepWpHD8yEu
+37Nd4cvv6mIW1Fgyfi75baC3vOVe96cSnNd9wAfRvjngqEgg0Exz8oyMPGaPwgYn
+hiH8NGsdjXcVr6nsB8K7dEo/r2olLVBqOoc4G5Qty29b8uhpS5IZVV3fKaGnKqUr
+7phRgx2yD2crFZT5BId55fkCgYEA0pk39zeoBVL4trrkF/kO6pEHkW/s0stf9oo3
+mYR5h+6VesltPaSNOBDXRzEBkLoR2qg8q0OA3LLjKl4cVnd+l0tJ3af6BViHyNgr
+OYOO7dx/+Qw7Ytuy4jDnOmbxo4yPWlh6EPWTXA/LoaoxDJrnG7oZswQBAnPu3I2I
+LGDY5lUCgYEAp/utnKRE/mXDFryMHJL2/srlg6EffzeM3ncpXhzZDmaKeMUadjKo
+vNmhneHA7CSZM5LjUAiw4LfRx1V4hrKVtYmtizXKBbGYVZDD4CSh52T8w4nxNN6D
++uw478XrZzjjuCWODpdIKfngo9ip9+TysUZuFdmE3xKRitmDvW//aRE=
+-----END RSA PRIVATE KEY-----
diff --git a/src/test/ssl/sslfiles.mk b/src/test/ssl/sslfiles.mk
new file mode 100644
index 0000000..5d5e137
--- /dev/null
+++ b/src/test/ssl/sslfiles.mk
@@ -0,0 +1,268 @@
+#-------------------------------------------------------------------------
+#
+# Makefile for sslfiles
+#
+# The SSL test files are completely disjoint from the rest of the build; they
+# don't rely on other targets or on Makefile.global. Since these recipes rely
+# on some default Make behavior that's disabled in the main build tree, such
+# as intermediate cleanup, they've been moved into their own separate file.
+# The main Makefile in this directory defers to this helper file when
+# building the sslfiles-related targets.
+#
+# Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
+# Portions Copyright (c) 1994, Regents of the University of California
+#
+# src/test/ssl/sslfiles.mk
+#
+#-------------------------------------------------------------------------
+
+#
+# To add a new server or client certificate, add a new <name>.config file in
+# the conf/ directory, then add <name> to either SERVERS or CLIENTS below. A
+# key/certificate pair will be generated for you, signed by the appropriate CA.
+#
+SERVERS := server-cn-and-alt-names \
+ server-cn-and-ip-alt-names \
+ server-cn-only \
+ server-ip-alt-names \
+ server-ip-cn-only \
+ server-ip-cn-and-alt-names \
+ server-ip-cn-and-dns-alt-names \
+ server-ip-in-dnsname \
+ server-single-alt-name \
+ server-multiple-alt-names \
+ server-no-names \
+ server-revoked
+CLIENTS := client client-dn client-revoked client_ext
+
+#
+# To add a new non-standard certificate, add it to SPECIAL_CERTS and then add
+# a recipe for creating it to the "Special-case certificates" section below.
+#
+SPECIAL_CERTS := ssl/server-rsapss.crt
+
+# Likewise for non-standard keys
+SPECIAL_KEYS := ssl/server-password.key \
+ ssl/client-der.key \
+ ssl/client-encrypted-pem.key \
+ ssl/client-encrypted-der.key \
+ ssl/server-rsapss.key
+
+#
+# These files are just concatenations of other files. You can add new ones to
+# COMBINATIONS here, then declare the constituent files as dependencies in the
+# "Combined files" section below.
+#
+COMBINATIONS := \
+ ssl/both-cas-1.crt \
+ ssl/both-cas-2.crt \
+ ssl/root+server_ca.crt \
+ ssl/root+server.crl \
+ ssl/root+client_ca.crt \
+ ssl/root+client.crl \
+ ssl/client+client_ca.crt
+
+CERTIFICATES := root_ca server_ca client_ca $(SERVERS) $(CLIENTS)
+STANDARD_CERTS := $(CERTIFICATES:%=ssl/%.crt)
+STANDARD_KEYS := $(CERTIFICATES:%=ssl/%.key)
+CRLS := ssl/root.crl \
+ ssl/client.crl \
+ ssl/server.crl
+
+SSLFILES := \
+ $(STANDARD_CERTS) \
+ $(STANDARD_KEYS) \
+ $(SPECIAL_CERTS) \
+ $(SPECIAL_KEYS) \
+ $(COMBINATIONS) \
+ $(CRLS)
+SSLDIRS := ssl/client-crldir \
+ ssl/server-crldir \
+ ssl/root+client-crldir \
+ ssl/root+server-crldir
+
+# This target re-generates all the key and certificate files. Usually we just
+# use the ones that are committed to the tree without rebuilding them.
+#
+.PHONY: sslfiles
+sslfiles: $(SSLFILES) $(SSLDIRS)
+
+#
+# Special-case certificates
+#
+
+# Root CA is self-signed.
+ssl/root_ca.crt: ssl/root_ca.key conf/root_ca.config
+ openssl req -new -x509 -config conf/root_ca.config -days 10000 -key $< -out $@
+
+# Certificate using RSA-PSS algorithm. Also self-signed.
+ssl/server-rsapss.crt: ssl/server-rsapss.key conf/server-rsapss.config
+ $(OPENSSL) req -new -x509 -config conf/server-rsapss.config -key $< -out $@
+
+#
+# Special-case keys
+#
+# All targets here are contained in $(SPECIAL_KEYS).
+#
+
+# Password-protected version of server-cn-only.key
+ssl/server-password.key: ssl/server-cn-only.key
+ openssl rsa -aes256 -in $< -out $@ -passout 'pass:secret1'
+
+# Key that uses the RSA-PSS algorithm
+ssl/server-rsapss.key:
+ $(OPENSSL) genpkey -algorithm rsa-pss -out $@
+
+# DER-encoded version of client.key
+ssl/client-der.key: ssl/client.key
+ openssl rsa -in $< -outform DER -out $@
+
+# Convert client.key to encrypted PEM (X.509 text) and DER (X.509 ASN.1)
+# formats to test libpq's support for the sslpassword= option.
+ssl/client-encrypted-pem.key: ssl/client.key
+ openssl rsa -in $< -outform PEM -aes128 -passout 'pass:dUmmyP^#+' -out $@
+# TODO Explicitly choosing -aes128 generates a key unusable to PostgreSQL with
+# OpenSSL 3.0.0, so fall back on the default for now.
+ssl/client-encrypted-der.key: ssl/client.key
+ openssl rsa -in $< -outform DER -passout 'pass:dUmmyP^#+' -out $@
+
+#
+# Combined files
+#
+# All targets in $(COMBINATIONS) share a single recipe; just declare the
+# necessary dependencies and they'll be smashed together.
+#
+
+# Root certificate file that contains both CA certificates, for testing
+# that multiple certificates can be used.
+ssl/both-cas-1.crt: ssl/root_ca.crt ssl/client_ca.crt ssl/server_ca.crt
+
+# The same, but the certs are in different order
+ssl/both-cas-2.crt: ssl/root_ca.crt ssl/server_ca.crt ssl/client_ca.crt
+
+# A root certificate file for the client, to validate server certs.
+ssl/root+server_ca.crt: ssl/root_ca.crt ssl/server_ca.crt
+
+# and for the server, to validate client certs
+ssl/root+client_ca.crt: ssl/root_ca.crt ssl/client_ca.crt
+
+# and for the client, to present to the server
+ssl/client+client_ca.crt: ssl/client.crt ssl/client_ca.crt
+
+# If a CRL is used, OpenSSL requires a CRL file for *all* the CAs in the
+# chain, even if some of them are empty.
+ssl/root+server.crl: ssl/root.crl ssl/server.crl
+ssl/root+client.crl: ssl/root.crl ssl/client.crl
+
+$(COMBINATIONS):
+ cat $^ > $@
+
+#
+# Standard keys
+#
+
+$(STANDARD_KEYS):
+ openssl genrsa -out $@ 2048
+ chmod 0600 $@
+
+#
+# Standard certificates
+#
+
+CA_CERTS := ssl/server_ca.crt ssl/client_ca.crt
+SERVER_CERTS := $(SERVERS:%=ssl/%.crt)
+CLIENT_CERTS := $(CLIENTS:%=ssl/%.crt)
+
+# See the "CA State" section below.
+root_ca_state_files := ssl/root_ca-certindex ssl/root_ca-certindex.attr ssl/root_ca.srl
+server_ca_state_files := ssl/server_ca-certindex ssl/server_ca-certindex.attr ssl/server_ca.srl
+client_ca_state_files := ssl/client_ca-certindex ssl/client_ca-certindex.attr ssl/client_ca.srl
+
+# These are the workhorse recipes. `openssl ca` can't be safely run from
+# parallel processes, so we must mark the entire Makefile .NOTPARALLEL.
+.NOTPARALLEL:
+$(CA_CERTS): ssl/%.crt: ssl/%.csr conf/%.config conf/cas.config ssl/root_ca.crt | ssl/new_certs_dir $(root_ca_state_files)
+ openssl ca -batch -config conf/cas.config -name root_ca -notext -in $< -out $@
+
+$(SERVER_CERTS): ssl/%.crt: ssl/%.csr conf/%.config conf/cas.config ssl/server_ca.crt | ssl/new_certs_dir $(server_ca_state_files)
+ openssl ca -batch -config conf/cas.config -name server_ca -notext -in $< -out $@
+
+$(CLIENT_CERTS): ssl/%.crt: ssl/%.csr conf/%.config conf/cas.config ssl/client_ca.crt | ssl/new_certs_dir $(client_ca_state_files)
+ openssl ca -batch -config conf/cas.config -name client_ca -notext -in $< -out $@
+
+# The CSRs don't need to persist after a build.
+.INTERMEDIATE: $(CERTIFICATES:%=ssl/%.csr)
+ssl/%.csr: ssl/%.key conf/%.config
+ openssl req -new -key $< -out $@ -config conf/$*.config
+
+#
+# CA State
+#
+# All of these are intended to be order-only dependencies; additionally, the
+# pattern recipes are marked as explicit intermediates. The goal is for Make to
+# create the state files once for each CA, allow them to accumulate whatever
+# state is needed, and then automatically remove them at the end of the run.
+#
+
+.INTERMEDIATE: $(root_ca_state_files) $(server_ca_state_files) $(client_ca_state_files)
+
+# OpenSSL requires a directory to put all generated certificates in. We don't
+# use this for anything, but we need a location.
+ssl/new_certs_dir:
+ mkdir $@
+
+ssl/%-certindex:
+ touch $@
+
+ssl/%-certindex.attr:
+ echo "unique_subject=no" > $@
+
+# The first serial number for each CA is based on the current timestamp, to
+# avoid collisions across Make runs.
+ssl/%.srl:
+ date +%Y%m%d%H%M%S00 > $@
+
+#
+# CRLs
+#
+
+ssl/root.crl: ssl/root_ca.crt | $(root_ca_state_files)
+ openssl ca -config conf/cas.config -name root_ca -gencrl -out $@
+
+ssl/server.crl: ssl/server-revoked.crt ssl/server_ca.crt | $(server_ca_state_files)
+ openssl ca -config conf/cas.config -name server_ca -revoke $<
+ openssl ca -config conf/cas.config -name server_ca -gencrl -out $@
+
+ssl/client.crl: ssl/client-revoked.crt ssl/client_ca.crt | $(client_ca_state_files)
+ openssl ca -config conf/cas.config -name client_ca -revoke $<
+ openssl ca -config conf/cas.config -name client_ca -gencrl -out $@
+
+#
+# CRL hash directories
+#
+
+ssl/root+server-crldir: ssl/server.crl ssl/root.crl
+ssl/root+client-crldir: ssl/client.crl ssl/root.crl
+ssl/server-crldir: ssl/server.crl
+ssl/client-crldir: ssl/client.crl
+
+crlhashfile = $(shell openssl crl -hash -noout -in $(1)).r0
+
+ssl/%-crldir:
+ mkdir -p $@
+ rm -f $@/*.r0
+ $(foreach crl,$^,cp $(crl) $@/$(call crlhashfile,$(crl)) &&) true
+ touch $@
+
+.PHONY: sslfiles-clean
+sslfiles-clean:
+ rm -f $(SSLFILES) ssl/*.old ssl/*.csr ssl/*.srl ssl/*-certindex*
+ rm -rf $(SSLDIRS) ssl/new_certs_dir
+
+# The difference between the below clean targets and sslfiles-clean is that the
+# clean targets will be run during a "standard" recursive clean run from the
+# main build tree. The sslfiles-clean target must be run explicitly from this
+# directory.
+.PHONY: clean distclean maintainer-clean
+clean distclean maintainer-clean:
+ rm -rf ssl/*.old ssl/new_certs_dir ssl/client*_tmp.key
diff --git a/src/test/ssl/t/001_ssltests.pl b/src/test/ssl/t/001_ssltests.pl
new file mode 100644
index 0000000..707f400
--- /dev/null
+++ b/src/test/ssl/t/001_ssltests.pl
@@ -0,0 +1,748 @@
+
+# Copyright (c) 2021-2022, PostgreSQL Global Development Group
+
+use strict;
+use warnings;
+use Config qw ( %Config );
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+use Test::More;
+
+use FindBin;
+use lib $FindBin::RealBin;
+
+use SSL::Server;
+
+if ($ENV{with_ssl} ne 'openssl')
+{
+ plan skip_all => 'OpenSSL not supported by this build';
+}
+
+my $ssl_server = SSL::Server->new();
+
+sub sslkey
+{
+ return $ssl_server->sslkey(@_);
+}
+
+sub switch_server_cert
+{
+ $ssl_server->switch_server_cert(@_);
+}
+#### 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;
+
+#### 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;
+
+# Run this before we lock down access below.
+my $result = $node->safe_psql('postgres', "SHOW ssl_library");
+is($result, $ssl_server->ssl_library(), 'ssl_library parameter');
+
+$ssl_server->configure_test_server_for_ssl($node, $SERVERHOSTADDR,
+ $SERVERHOSTCIDR, 'trust');
+
+note "testing password-protected keys";
+
+switch_server_cert(
+ $node,
+ certfile => 'server-cn-only',
+ cafile => 'root+client_ca',
+ keyfile => 'server-password',
+ passphrase_cmd => 'echo wrongpassword',
+ restart => 'no');
+
+command_fails(
+ [ 'pg_ctl', '-D', $node->data_dir, '-l', $node->logfile, 'restart' ],
+ 'restart fails with password-protected key file with wrong password');
+$node->_update_pid(0);
+
+switch_server_cert(
+ $node,
+ certfile => 'server-cn-only',
+ cafile => 'root+client_ca',
+ keyfile => 'server-password',
+ passphrase_cmd => 'echo secret1',
+ restart => 'no');
+
+command_ok(
+ [ 'pg_ctl', '-D', $node->data_dir, '-l', $node->logfile, 'restart' ],
+ 'restart succeeds with password-protected key file');
+$node->_update_pid(1);
+
+# Test compatibility of SSL protocols.
+# TLSv1.1 is lower than TLSv1.2, so it won't work.
+$node->append_conf(
+ 'postgresql.conf',
+ qq{ssl_min_protocol_version='TLSv1.2'
+ssl_max_protocol_version='TLSv1.1'});
+command_fails(
+ [ 'pg_ctl', '-D', $node->data_dir, '-l', $node->logfile, 'restart' ],
+ 'restart fails with incorrect SSL protocol bounds');
+# Go back to the defaults, this works.
+$node->append_conf(
+ 'postgresql.conf',
+ qq{ssl_min_protocol_version='TLSv1.2'
+ssl_max_protocol_version=''});
+command_ok(
+ [ 'pg_ctl', '-D', $node->data_dir, '-l', $node->logfile, 'restart' ],
+ 'restart succeeds with correct SSL protocol bounds');
+
+### Run client-side tests.
+###
+### Test that libpq accepts/rejects the connection correctly, depending
+### on sslmode and whether the server's certificate looks correct. No
+### client certificate is used in these tests.
+
+note "running client tests";
+
+switch_server_cert($node, certfile => 'server-cn-only');
+
+# Set of default settings for SSL parameters in connection string. This
+# makes the tests protected against any defaults the environment may have
+# in ~/.postgresql/.
+my $default_ssl_connstr =
+ "sslkey=invalid sslcert=invalid sslrootcert=invalid sslcrl=invalid sslcrldir=invalid";
+
+$common_connstr =
+ "$default_ssl_connstr user=ssltestuser dbname=trustdb hostaddr=$SERVERHOSTADDR host=common-name.pg-ssltest.test";
+
+# The server should not accept non-SSL connections.
+$node->connect_fails(
+ "$common_connstr sslmode=disable",
+ "server doesn't accept non-SSL connections",
+ expected_stderr => qr/\Qno pg_hba.conf entry\E/);
+
+# Try without a root cert. In sslmode=require, this should work. In verify-ca
+# or verify-full mode it should fail.
+$node->connect_ok(
+ "$common_connstr sslrootcert=invalid sslmode=require",
+ "connect without server root cert sslmode=require");
+$node->connect_fails(
+ "$common_connstr sslrootcert=invalid sslmode=verify-ca",
+ "connect without server root cert sslmode=verify-ca",
+ expected_stderr => qr/root certificate file "invalid" does not exist/);
+$node->connect_fails(
+ "$common_connstr sslrootcert=invalid sslmode=verify-full",
+ "connect without server root cert sslmode=verify-full",
+ expected_stderr => qr/root certificate file "invalid" does not exist/);
+
+# Try with wrong root cert, should fail. (We're using the client CA as the
+# root, but the server's key is signed by the server CA.)
+$node->connect_fails(
+ "$common_connstr sslrootcert=ssl/client_ca.crt sslmode=require",
+ "connect with wrong server root cert sslmode=require",
+ expected_stderr => qr/SSL error: certificate verify failed/);
+$node->connect_fails(
+ "$common_connstr sslrootcert=ssl/client_ca.crt sslmode=verify-ca",
+ "connect with wrong server root cert sslmode=verify-ca",
+ expected_stderr => qr/SSL error: certificate verify failed/);
+$node->connect_fails(
+ "$common_connstr sslrootcert=ssl/client_ca.crt sslmode=verify-full",
+ "connect with wrong server root cert sslmode=verify-full",
+ expected_stderr => qr/SSL error: certificate verify failed/);
+
+# Try with just the server CA's cert. This fails because the root file
+# must contain the whole chain up to the root CA.
+$node->connect_fails(
+ "$common_connstr sslrootcert=ssl/server_ca.crt sslmode=verify-ca",
+ "connect with server CA cert, without root CA",
+ expected_stderr => qr/SSL error: certificate verify failed/);
+
+# And finally, with the correct root cert.
+$node->connect_ok(
+ "$common_connstr sslrootcert=ssl/root+server_ca.crt sslmode=require",
+ "connect with correct server CA cert file sslmode=require");
+$node->connect_ok(
+ "$common_connstr sslrootcert=ssl/root+server_ca.crt sslmode=verify-ca",
+ "connect with correct server CA cert file sslmode=verify-ca");
+$node->connect_ok(
+ "$common_connstr sslrootcert=ssl/root+server_ca.crt sslmode=verify-full",
+ "connect with correct server CA cert file sslmode=verify-full");
+
+# Test with cert root file that contains two certificates. The client should
+# be able to pick the right one, regardless of the order in the file.
+$node->connect_ok(
+ "$common_connstr sslrootcert=ssl/both-cas-1.crt sslmode=verify-ca",
+ "cert root file that contains two certificates, order 1");
+$node->connect_ok(
+ "$common_connstr sslrootcert=ssl/both-cas-2.crt sslmode=verify-ca",
+ "cert root file that contains two certificates, order 2");
+
+# CRL tests
+
+# Invalid CRL filename is the same as no CRL, succeeds
+$node->connect_ok(
+ "$common_connstr sslrootcert=ssl/root+server_ca.crt sslmode=verify-ca sslcrl=invalid",
+ "sslcrl option with invalid file name");
+
+# A CRL belonging to a different CA is not accepted, fails
+$node->connect_fails(
+ "$common_connstr sslrootcert=ssl/root+server_ca.crt sslmode=verify-ca sslcrl=ssl/client.crl",
+ "CRL belonging to a different CA",
+ expected_stderr => qr/SSL error: certificate verify failed/);
+
+# The same for CRL directory. sslcrl='' is added here to override the
+# invalid default, so as this does not interfere with this case.
+$node->connect_fails(
+ "$common_connstr sslcrl='' sslrootcert=ssl/root+server_ca.crt sslmode=verify-ca sslcrldir=ssl/client-crldir",
+ "directory CRL belonging to a different CA",
+ expected_stderr => qr/SSL error: certificate verify failed/);
+
+# With the correct CRL, succeeds (this cert is not revoked)
+$node->connect_ok(
+ "$common_connstr sslrootcert=ssl/root+server_ca.crt sslmode=verify-ca sslcrl=ssl/root+server.crl",
+ "CRL with a non-revoked cert");
+
+# The same for CRL directory
+$node->connect_ok(
+ "$common_connstr sslrootcert=ssl/root+server_ca.crt sslmode=verify-ca sslcrldir=ssl/root+server-crldir",
+ "directory CRL with a non-revoked cert");
+
+# Check that connecting with verify-full fails, when the hostname doesn't
+# match the hostname in the server's certificate.
+$common_connstr =
+ "$default_ssl_connstr user=ssltestuser dbname=trustdb sslrootcert=ssl/root+server_ca.crt hostaddr=$SERVERHOSTADDR";
+
+$node->connect_ok("$common_connstr sslmode=require host=wronghost.test",
+ "mismatch between host name and server certificate sslmode=require");
+$node->connect_ok(
+ "$common_connstr sslmode=verify-ca host=wronghost.test",
+ "mismatch between host name and server certificate sslmode=verify-ca");
+$node->connect_fails(
+ "$common_connstr sslmode=verify-full host=wronghost.test",
+ "mismatch between host name and server certificate sslmode=verify-full",
+ expected_stderr =>
+ qr/\Qserver certificate for "common-name.pg-ssltest.test" does not match host name "wronghost.test"\E/
+);
+
+# Test with an IP address in the Common Name. This is a strange corner case that
+# nevertheless is supported, as long as the address string matches exactly.
+switch_server_cert($node, certfile => 'server-ip-cn-only');
+
+$common_connstr =
+ "$default_ssl_connstr user=ssltestuser dbname=trustdb sslrootcert=ssl/root+server_ca.crt hostaddr=$SERVERHOSTADDR sslmode=verify-full";
+
+$node->connect_ok("$common_connstr host=192.0.2.1",
+ "IP address in the Common Name");
+
+$node->connect_fails(
+ "$common_connstr host=192.000.002.001",
+ "mismatch between host name and server certificate IP address",
+ expected_stderr =>
+ qr/\Qserver certificate for "192.0.2.1" does not match host name "192.000.002.001"\E/
+);
+
+# Similarly, we'll also match an IP address in a dNSName SAN. (This is
+# long-standing behavior.)
+switch_server_cert($node, certfile => 'server-ip-in-dnsname');
+
+$node->connect_ok("$common_connstr host=192.0.2.1",
+ "IP address in a dNSName");
+
+# Test Subject Alternative Names.
+switch_server_cert($node, certfile => 'server-multiple-alt-names');
+
+$common_connstr =
+ "$default_ssl_connstr user=ssltestuser dbname=trustdb sslrootcert=ssl/root+server_ca.crt hostaddr=$SERVERHOSTADDR sslmode=verify-full";
+
+$node->connect_ok(
+ "$common_connstr host=dns1.alt-name.pg-ssltest.test",
+ "host name matching with X.509 Subject Alternative Names 1");
+$node->connect_ok(
+ "$common_connstr host=dns2.alt-name.pg-ssltest.test",
+ "host name matching with X.509 Subject Alternative Names 2");
+$node->connect_ok("$common_connstr host=foo.wildcard.pg-ssltest.test",
+ "host name matching with X.509 Subject Alternative Names wildcard");
+
+$node->connect_fails(
+ "$common_connstr host=wronghost.alt-name.pg-ssltest.test",
+ "host name not matching with X.509 Subject Alternative Names",
+ expected_stderr =>
+ qr/\Qserver certificate for "dns1.alt-name.pg-ssltest.test" (and 2 other names) does not match host name "wronghost.alt-name.pg-ssltest.test"\E/
+);
+$node->connect_fails(
+ "$common_connstr host=deep.subdomain.wildcard.pg-ssltest.test",
+ "host name not matching with X.509 Subject Alternative Names wildcard",
+ expected_stderr =>
+ qr/\Qserver certificate for "dns1.alt-name.pg-ssltest.test" (and 2 other names) does not match host name "deep.subdomain.wildcard.pg-ssltest.test"\E/
+);
+
+# Test certificate with a single Subject Alternative Name. (this gives a
+# slightly different error message, that's all)
+switch_server_cert($node, certfile => 'server-single-alt-name');
+
+$common_connstr =
+ "$default_ssl_connstr user=ssltestuser dbname=trustdb sslrootcert=ssl/root+server_ca.crt hostaddr=$SERVERHOSTADDR sslmode=verify-full";
+
+$node->connect_ok(
+ "$common_connstr host=single.alt-name.pg-ssltest.test",
+ "host name matching with a single X.509 Subject Alternative Name");
+
+$node->connect_fails(
+ "$common_connstr host=wronghost.alt-name.pg-ssltest.test",
+ "host name not matching with a single X.509 Subject Alternative Name",
+ expected_stderr =>
+ qr/\Qserver certificate for "single.alt-name.pg-ssltest.test" does not match host name "wronghost.alt-name.pg-ssltest.test"\E/
+);
+$node->connect_fails(
+ "$common_connstr host=deep.subdomain.wildcard.pg-ssltest.test",
+ "host name not matching with a single X.509 Subject Alternative Name wildcard",
+ expected_stderr =>
+ qr/\Qserver certificate for "single.alt-name.pg-ssltest.test" does not match host name "deep.subdomain.wildcard.pg-ssltest.test"\E/
+);
+
+SKIP:
+{
+ skip 'IPv6 addresses in certificates not support on this platform', 1
+ unless check_pg_config('#define HAVE_INET_PTON 1');
+
+ # Test certificate with IP addresses in the SANs.
+ switch_server_cert($node, certfile => 'server-ip-alt-names');
+
+ $node->connect_ok("$common_connstr host=192.0.2.1",
+ "host matching an IPv4 address (Subject Alternative Name 1)");
+
+ $node->connect_ok(
+ "$common_connstr host=192.000.002.001",
+ "host matching an IPv4 address in alternate form (Subject Alternative Name 1)"
+ );
+
+ $node->connect_fails(
+ "$common_connstr host=192.0.2.2",
+ "host not matching an IPv4 address (Subject Alternative Name 1)",
+ expected_stderr =>
+ qr/\Qserver certificate for "192.0.2.1" (and 1 other name) does not match host name "192.0.2.2"\E/
+ );
+
+ $node->connect_ok("$common_connstr host=2001:DB8::1",
+ "host matching an IPv6 address (Subject Alternative Name 2)");
+
+ $node->connect_ok(
+ "$common_connstr host=2001:db8:0:0:0:0:0:1",
+ "host matching an IPv6 address in alternate form (Subject Alternative Name 2)"
+ );
+
+ $node->connect_ok(
+ "$common_connstr host=2001:db8::0.0.0.1",
+ "host matching an IPv6 address in mixed form (Subject Alternative Name 2)"
+ );
+
+ $node->connect_fails(
+ "$common_connstr host=::1",
+ "host not matching an IPv6 address (Subject Alternative Name 2)",
+ expected_stderr =>
+ qr/\Qserver certificate for "192.0.2.1" (and 1 other name) does not match host name "::1"\E/
+ );
+
+ $node->connect_fails(
+ "$common_connstr host=2001:DB8::1/128",
+ "IPv6 host with CIDR mask does not match",
+ expected_stderr =>
+ qr/\Qserver certificate for "192.0.2.1" (and 1 other name) does not match host name "2001:DB8::1\/128"\E/
+ );
+}
+
+# Test server certificate with a CN and DNS SANs. Per RFCs 2818 and 6125, the CN
+# should be ignored when the certificate has both.
+switch_server_cert($node, certfile => 'server-cn-and-alt-names');
+
+$common_connstr =
+ "$default_ssl_connstr user=ssltestuser dbname=trustdb sslrootcert=ssl/root+server_ca.crt hostaddr=$SERVERHOSTADDR sslmode=verify-full";
+
+$node->connect_ok("$common_connstr host=dns1.alt-name.pg-ssltest.test",
+ "certificate with both a CN and SANs 1");
+$node->connect_ok("$common_connstr host=dns2.alt-name.pg-ssltest.test",
+ "certificate with both a CN and SANs 2");
+$node->connect_fails(
+ "$common_connstr host=common-name.pg-ssltest.test",
+ "certificate with both a CN and SANs ignores CN",
+ expected_stderr =>
+ qr/\Qserver certificate for "dns1.alt-name.pg-ssltest.test" (and 1 other name) does not match host name "common-name.pg-ssltest.test"\E/
+);
+
+SKIP:
+{
+ skip 'IPv6 addresses in certificates not support on this platform', 1
+ unless check_pg_config('#define HAVE_INET_PTON 1');
+
+ # But we will fall back to check the CN if the SANs contain only IP addresses.
+ switch_server_cert($node, certfile => 'server-cn-and-ip-alt-names');
+
+ $node->connect_ok(
+ "$common_connstr host=common-name.pg-ssltest.test",
+ "certificate with both a CN and IP SANs matches CN");
+ $node->connect_ok("$common_connstr host=192.0.2.1",
+ "certificate with both a CN and IP SANs matches SAN 1");
+ $node->connect_ok("$common_connstr host=2001:db8::1",
+ "certificate with both a CN and IP SANs matches SAN 2");
+
+ # And now the same tests, but with IP addresses and DNS names swapped.
+ switch_server_cert($node, certfile => 'server-ip-cn-and-alt-names');
+
+ $node->connect_ok("$common_connstr host=192.0.2.2",
+ "certificate with both an IP CN and IP SANs 1");
+ $node->connect_ok("$common_connstr host=2001:db8::1",
+ "certificate with both an IP CN and IP SANs 2");
+ $node->connect_fails(
+ "$common_connstr host=192.0.2.1",
+ "certificate with both an IP CN and IP SANs ignores CN",
+ expected_stderr =>
+ qr/\Qserver certificate for "192.0.2.2" (and 1 other name) does not match host name "192.0.2.1"\E/
+ );
+}
+
+switch_server_cert($node, certfile => 'server-ip-cn-and-dns-alt-names');
+
+$node->connect_ok("$common_connstr host=192.0.2.1",
+ "certificate with both an IP CN and DNS SANs matches CN");
+$node->connect_ok(
+ "$common_connstr host=dns1.alt-name.pg-ssltest.test",
+ "certificate with both an IP CN and DNS SANs matches SAN 1");
+$node->connect_ok(
+ "$common_connstr host=dns2.alt-name.pg-ssltest.test",
+ "certificate with both an IP CN and DNS SANs matches SAN 2");
+
+# Finally, test a server certificate that has no CN or SANs. Of course, that's
+# not a very sensible certificate, but libpq should handle it gracefully.
+switch_server_cert($node, certfile => 'server-no-names');
+$common_connstr =
+ "$default_ssl_connstr user=ssltestuser dbname=trustdb sslrootcert=ssl/root+server_ca.crt hostaddr=$SERVERHOSTADDR";
+
+$node->connect_ok(
+ "$common_connstr sslmode=verify-ca host=common-name.pg-ssltest.test",
+ "server certificate without CN or SANs sslmode=verify-ca");
+$node->connect_fails(
+ $common_connstr . " "
+ . "sslmode=verify-full host=common-name.pg-ssltest.test",
+ "server certificate without CN or SANs sslmode=verify-full",
+ expected_stderr =>
+ qr/could not get server's host name from server certificate/);
+
+# Test that the CRL works
+switch_server_cert($node, certfile => 'server-revoked');
+
+$common_connstr =
+ "$default_ssl_connstr user=ssltestuser dbname=trustdb hostaddr=$SERVERHOSTADDR host=common-name.pg-ssltest.test";
+
+# Without the CRL, succeeds. With it, fails.
+$node->connect_ok(
+ "$common_connstr sslrootcert=ssl/root+server_ca.crt sslmode=verify-ca",
+ "connects without client-side CRL");
+$node->connect_fails(
+ "$common_connstr sslrootcert=ssl/root+server_ca.crt sslmode=verify-ca sslcrl=ssl/root+server.crl",
+ "does not connect with client-side CRL file",
+ expected_stderr => qr/SSL error: certificate verify failed/);
+# sslcrl='' is added here to override the invalid default, so as this
+# does not interfere with this case.
+$node->connect_fails(
+ "$common_connstr sslcrl='' sslrootcert=ssl/root+server_ca.crt sslmode=verify-ca sslcrldir=ssl/root+server-crldir",
+ "does not connect with client-side CRL directory",
+ expected_stderr => qr/SSL error: certificate verify failed/);
+
+# pg_stat_ssl
+command_like(
+ [
+ 'psql', '-X',
+ '-A', '-F',
+ ',', '-P',
+ 'null=_null_', '-d',
+ "$common_connstr sslrootcert=invalid", '-c',
+ "SELECT * FROM pg_stat_ssl WHERE pid = pg_backend_pid()"
+ ],
+ qr{^pid,ssl,version,cipher,bits,client_dn,client_serial,issuer_dn\r?\n
+ ^\d+,t,TLSv[\d.]+,[\w-]+,\d+,_null_,_null_,_null_\r?$}mx,
+ 'pg_stat_ssl view without client certificate');
+
+# Test min/max SSL protocol versions.
+$node->connect_ok(
+ "$common_connstr sslrootcert=ssl/root+server_ca.crt sslmode=require ssl_min_protocol_version=TLSv1.2 ssl_max_protocol_version=TLSv1.2",
+ "connection success with correct range of TLS protocol versions");
+$node->connect_fails(
+ "$common_connstr sslrootcert=ssl/root+server_ca.crt sslmode=require ssl_min_protocol_version=TLSv1.2 ssl_max_protocol_version=TLSv1.1",
+ "connection failure with incorrect range of TLS protocol versions",
+ expected_stderr => qr/invalid SSL protocol version range/);
+$node->connect_fails(
+ "$common_connstr sslrootcert=ssl/root+server_ca.crt sslmode=require ssl_min_protocol_version=incorrect_tls",
+ "connection failure with an incorrect SSL protocol minimum bound",
+ expected_stderr => qr/invalid ssl_min_protocol_version value/);
+$node->connect_fails(
+ "$common_connstr sslrootcert=ssl/root+server_ca.crt sslmode=require ssl_max_protocol_version=incorrect_tls",
+ "connection failure with an incorrect SSL protocol maximum bound",
+ expected_stderr => qr/invalid ssl_max_protocol_version value/);
+
+### Server-side tests.
+###
+### Test certificate authorization.
+
+note "running server tests";
+
+$common_connstr =
+ "$default_ssl_connstr sslrootcert=ssl/root+server_ca.crt sslmode=require dbname=certdb hostaddr=$SERVERHOSTADDR host=localhost";
+
+# no client cert
+$node->connect_fails(
+ "$common_connstr user=ssltestuser sslcert=invalid",
+ "certificate authorization fails without client cert",
+ expected_stderr => qr/connection requires a valid client certificate/);
+
+# correct client cert in unencrypted PEM
+$node->connect_ok(
+ "$common_connstr user=ssltestuser sslcert=ssl/client.crt "
+ . sslkey('client.key'),
+ "certificate authorization succeeds with correct client cert in PEM format"
+);
+
+# correct client cert in unencrypted DER
+$node->connect_ok(
+ "$common_connstr user=ssltestuser sslcert=ssl/client.crt "
+ . sslkey('client-der.key'),
+ "certificate authorization succeeds with correct client cert in DER format"
+);
+
+# correct client cert in encrypted PEM
+$node->connect_ok(
+ "$common_connstr user=ssltestuser sslcert=ssl/client.crt "
+ . sslkey('client-encrypted-pem.key')
+ . " sslpassword='dUmmyP^#+'",
+ "certificate authorization succeeds with correct client cert in encrypted PEM format"
+);
+
+# correct client cert in encrypted DER
+$node->connect_ok(
+ "$common_connstr user=ssltestuser sslcert=ssl/client.crt "
+ . sslkey('client-encrypted-der.key')
+ . " sslpassword='dUmmyP^#+'",
+ "certificate authorization succeeds with correct client cert in encrypted DER format"
+);
+
+# correct client cert in encrypted PEM with wrong password
+$node->connect_fails(
+ "$common_connstr user=ssltestuser sslcert=ssl/client.crt "
+ . sslkey('client-encrypted-pem.key')
+ . " sslpassword='wrong'",
+ "certificate authorization fails with correct client cert and wrong password in encrypted PEM format",
+ expected_stderr =>
+ qr!private key file \".*client-encrypted-pem\.key\": bad decrypt!,);
+
+
+# correct client cert using whole DN
+my $dn_connstr = "$common_connstr dbname=certdb_dn";
+
+$node->connect_ok(
+ "$dn_connstr user=ssltestuser sslcert=ssl/client-dn.crt "
+ . sslkey('client-dn.key'),
+ "certificate authorization succeeds with DN mapping",
+ log_like => [
+ qr/connection authenticated: identity="CN=ssltestuser-dn,OU=Testing,OU=Engineering,O=PGDG" method=cert/
+ ],);
+
+# same thing but with a regex
+$dn_connstr = "$common_connstr dbname=certdb_dn_re";
+
+$node->connect_ok(
+ "$dn_connstr user=ssltestuser sslcert=ssl/client-dn.crt "
+ . sslkey('client-dn.key'),
+ "certificate authorization succeeds with DN regex mapping");
+
+# same thing but using explicit CN
+$dn_connstr = "$common_connstr dbname=certdb_cn";
+
+$node->connect_ok(
+ "$dn_connstr user=ssltestuser sslcert=ssl/client-dn.crt "
+ . sslkey('client-dn.key'),
+ "certificate authorization succeeds with CN mapping",
+ # the full DN should still be used as the authenticated identity
+ log_like => [
+ qr/connection authenticated: identity="CN=ssltestuser-dn,OU=Testing,OU=Engineering,O=PGDG" method=cert/
+ ],);
+
+
+
+TODO:
+{
+ # these tests are left here waiting on us to get better pty support
+ # so they don't hang. For now they are not performed.
+
+ todo_skip "Need Pty support", 4;
+
+ # correct client cert in encrypted PEM with empty password
+ $node->connect_fails(
+ "$common_connstr user=ssltestuser sslcert=ssl/client.crt "
+ . sslkey('client-encrypted-pem.key')
+ . " sslpassword=''",
+ "certificate authorization fails with correct client cert and empty password in encrypted PEM format",
+ expected_stderr =>
+ qr!private key file \".*client-encrypted-pem\.key\": processing error!
+ );
+
+ # correct client cert in encrypted PEM with no password
+ $node->connect_fails(
+ "$common_connstr user=ssltestuser sslcert=ssl/client.crt "
+ . sslkey('client-encrypted-pem.key'),
+ "certificate authorization fails with correct client cert and no password in encrypted PEM format",
+ expected_stderr =>
+ qr!private key file \".*client-encrypted-pem\.key\": processing error!
+ );
+
+}
+
+# pg_stat_ssl
+
+my $serialno = `openssl x509 -serial -noout -in ssl/client.crt`;
+if ($? == 0)
+{
+ # OpenSSL prints serial numbers in hexadecimal and converting the serial
+ # from hex requires a 64-bit capable Perl as the serialnumber is based on
+ # the current timestamp. On 32-bit fall back to checking for it being an
+ # integer like how we do when grabbing the serial fails.
+ if ($Config{ivsize} == 8)
+ {
+ $serialno =~ s/^serial=//;
+ $serialno =~ s/\s+//g;
+ $serialno = hex($serialno);
+ }
+ else
+ {
+ $serialno = '\d+';
+ }
+}
+else
+{
+ # OpenSSL isn't functioning on the user's PATH. This probably isn't worth
+ # skipping the test over, so just fall back to a generic integer match.
+ warn 'couldn\'t run `openssl x509` to get client cert serialno';
+ $serialno = '\d+';
+}
+
+command_like(
+ [
+ 'psql',
+ '-X',
+ '-A',
+ '-F',
+ ',',
+ '-P',
+ 'null=_null_',
+ '-d',
+ "$common_connstr user=ssltestuser sslcert=ssl/client.crt "
+ . sslkey('client.key'),
+ '-c',
+ "SELECT * FROM pg_stat_ssl WHERE pid = pg_backend_pid()"
+ ],
+ qr{^pid,ssl,version,cipher,bits,client_dn,client_serial,issuer_dn\r?\n
+ ^\d+,t,TLSv[\d.]+,[\w-]+,\d+,/?CN=ssltestuser,$serialno,/?\QCN=Test CA for PostgreSQL SSL regression test client certs\E\r?$}mx,
+ 'pg_stat_ssl with client certificate');
+
+# client key with wrong permissions
+SKIP:
+{
+ skip "Permissions check not enforced on Windows", 2 if ($windows_os);
+
+ $node->connect_fails(
+ "$common_connstr user=ssltestuser sslcert=ssl/client.crt "
+ . sslkey('client_wrongperms.key'),
+ "certificate authorization fails because of file permissions",
+ expected_stderr =>
+ qr!private key file \".*client_wrongperms\.key\" has group or world access!
+ );
+}
+
+# client cert belonging to another user
+$node->connect_fails(
+ "$common_connstr user=anotheruser sslcert=ssl/client.crt "
+ . sslkey('client.key'),
+ "certificate authorization fails with client cert belonging to another user",
+ expected_stderr =>
+ qr/certificate authentication failed for user "anotheruser"/,
+ # certificate authentication should be logged even on failure
+ log_like =>
+ [qr/connection authenticated: identity="CN=ssltestuser" method=cert/],);
+
+# revoked client cert
+$node->connect_fails(
+ "$common_connstr user=ssltestuser sslcert=ssl/client-revoked.crt "
+ . sslkey('client-revoked.key'),
+ "certificate authorization fails with revoked client cert",
+ expected_stderr => qr/SSL error: sslv3 alert certificate revoked/,
+ # revoked certificates should not authenticate the user
+ log_unlike => [qr/connection authenticated:/],);
+
+# Check that connecting with auth-option verify-full in pg_hba:
+# works, iff username matches Common Name
+# fails, iff username doesn't match Common Name.
+$common_connstr =
+ "$default_ssl_connstr sslrootcert=ssl/root+server_ca.crt sslmode=require dbname=verifydb hostaddr=$SERVERHOSTADDR host=localhost";
+
+$node->connect_ok(
+ "$common_connstr user=ssltestuser sslcert=ssl/client.crt "
+ . sslkey('client.key'),
+ "auth_option clientcert=verify-full succeeds with matching username and Common Name",
+ # verify-full does not provide authentication
+ log_unlike => [qr/connection authenticated:/],);
+
+$node->connect_fails(
+ "$common_connstr user=anotheruser sslcert=ssl/client.crt "
+ . sslkey('client.key'),
+ "auth_option clientcert=verify-full fails with mismatching username and Common Name",
+ expected_stderr =>
+ qr/FATAL: .* "trust" authentication failed for user "anotheruser"/,
+ # verify-full does not provide authentication
+ log_unlike => [qr/connection authenticated:/],);
+
+# Check that connecting with auth-option verify-ca in pg_hba :
+# works, when username doesn't match Common Name
+$node->connect_ok(
+ "$common_connstr user=yetanotheruser sslcert=ssl/client.crt "
+ . sslkey('client.key'),
+ "auth_option clientcert=verify-ca succeeds with mismatching username and Common Name",
+ # verify-full does not provide authentication
+ log_unlike => [qr/connection authenticated:/],);
+
+# intermediate client_ca.crt is provided by client, and isn't in server's ssl_ca_file
+switch_server_cert($node, certfile => 'server-cn-only', cafile => 'root_ca');
+$common_connstr =
+ "$default_ssl_connstr user=ssltestuser dbname=certdb "
+ . sslkey('client.key')
+ . " sslrootcert=ssl/root+server_ca.crt hostaddr=$SERVERHOSTADDR host=localhost";
+
+$node->connect_ok(
+ "$common_connstr sslmode=require sslcert=ssl/client+client_ca.crt",
+ "intermediate client certificate is provided by client");
+$node->connect_fails(
+ $common_connstr . " " . "sslmode=require sslcert=ssl/client.crt",
+ "intermediate client certificate is missing",
+ expected_stderr => qr/SSL error: tlsv1 alert unknown ca/);
+
+# test server-side CRL directory
+switch_server_cert(
+ $node,
+ certfile => 'server-cn-only',
+ crldir => 'root+client-crldir');
+
+# revoked client cert
+$node->connect_fails(
+ "$common_connstr user=ssltestuser sslcert=ssl/client-revoked.crt "
+ . sslkey('client-revoked.key'),
+ "certificate authorization fails with revoked client cert with server-side CRL directory",
+ expected_stderr => qr/SSL error: sslv3 alert certificate revoked/);
+
+done_testing();
diff --git a/src/test/ssl/t/002_scram.pl b/src/test/ssl/t/002_scram.pl
new file mode 100644
index 0000000..566cb12
--- /dev/null
+++ b/src/test/ssl/t/002_scram.pl
@@ -0,0 +1,152 @@
+
+# Copyright (c) 2021-2022, PostgreSQL Global Development Group
+
+# Test SCRAM authentication and TLS channel binding types
+
+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 SSL::Server;
+
+if ($ENV{with_ssl} ne 'openssl')
+{
+ plan skip_all => 'OpenSSL not supported by this build';
+}
+
+my $ssl_server = SSL::Server->new();
+
+sub sslkey
+{
+ return $ssl_server->sslkey(@_);
+}
+
+sub switch_server_cert
+{
+ $ssl_server->switch_server_cert(@_);
+}
+
+
+# This is the hostname used to connect to the server.
+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';
+
+# Determine whether build supports tls-server-end-point.
+my $supports_tls_server_end_point =
+ check_pg_config("#define HAVE_X509_GET_SIGNATURE_NID 1");
+# Determine whether build supports detection of hash algorithms for
+# RSA-PSS certificates.
+my $supports_rsapss_certs =
+ check_pg_config("#define HAVE_X509_GET_SIGNATURE_INFO 1");
+
+# Allocation of base connection string shared among multiple tests.
+my $common_connstr;
+
+# 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 server for SSL connections, with password handling.
+$ssl_server->configure_test_server_for_ssl(
+ $node, $SERVERHOSTADDR, $SERVERHOSTCIDR,
+ "scram-sha-256",
+ 'password' => "pass",
+ 'password_enc' => "scram-sha-256");
+switch_server_cert($node, certfile => 'server-cn-only');
+$ENV{PGPASSWORD} = "pass";
+$common_connstr =
+ "dbname=trustdb sslmode=require sslcert=invalid sslrootcert=invalid hostaddr=$SERVERHOSTADDR host=localhost";
+
+# Default settings
+$node->connect_ok(
+ "$common_connstr user=ssltestuser",
+ "Basic SCRAM authentication with SSL");
+
+# Test channel_binding
+$node->connect_fails(
+ "$common_connstr user=ssltestuser channel_binding=invalid_value",
+ "SCRAM with SSL and channel_binding=invalid_value",
+ expected_stderr => qr/invalid channel_binding value: "invalid_value"/);
+$node->connect_ok("$common_connstr user=ssltestuser channel_binding=disable",
+ "SCRAM with SSL and channel_binding=disable");
+if ($supports_tls_server_end_point)
+{
+ $node->connect_ok(
+ "$common_connstr user=ssltestuser channel_binding=require",
+ "SCRAM with SSL and channel_binding=require");
+}
+else
+{
+ $node->connect_fails(
+ "$common_connstr user=ssltestuser channel_binding=require",
+ "SCRAM with SSL and channel_binding=require",
+ expected_stderr =>
+ qr/channel binding is required, but server did not offer an authentication method that supports channel binding/
+ );
+}
+
+# Now test when the user has an MD5-encrypted password; should fail
+$node->connect_fails(
+ "$common_connstr user=md5testuser channel_binding=require",
+ "MD5 with SSL and channel_binding=require",
+ expected_stderr =>
+ qr/channel binding required but not supported by server's authentication request/
+);
+
+# Now test with auth method 'cert' by connecting to 'certdb'. Should fail,
+# because channel binding is not performed. Note that ssl/client.key may
+# be used in a different test, so the name of this temporary client key
+# is chosen here to be unique.
+my $cert_tempdir = PostgreSQL::Test::Utils::tempdir();
+my $client_tmp_key = "$cert_tempdir/client_scram.key";
+copy("ssl/client.key", "$cert_tempdir/client_scram.key")
+ or die
+ "couldn't copy ssl/client_key to $cert_tempdir/client_scram.key for permission change: $!";
+chmod 0600, "$cert_tempdir/client_scram.key"
+ or die "failed to change permissions on $cert_tempdir/client_scram.key: $!";
+$client_tmp_key =~ s!\\!/!g if $PostgreSQL::Test::Utils::windows_os;
+$node->connect_fails(
+ "sslcert=ssl/client.crt sslkey=$client_tmp_key sslrootcert=invalid hostaddr=$SERVERHOSTADDR host=localhost dbname=certdb user=ssltestuser channel_binding=require",
+ "Cert authentication and channel_binding=require",
+ expected_stderr =>
+ qr/channel binding required, but server authenticated client without channel binding/
+);
+
+# Certificate verification at the connection level should still work fine.
+$node->connect_ok(
+ "sslcert=ssl/client.crt sslkey=$client_tmp_key sslrootcert=invalid hostaddr=$SERVERHOSTADDR host=localhost dbname=verifydb user=ssltestuser",
+ "SCRAM with clientcert=verify-full",
+ log_like => [
+ qr/connection authenticated: identity="ssltestuser" method=scram-sha-256/
+ ]);
+
+# Now test with a server certificate that uses the RSA-PSS algorithm.
+# This checks that the certificate can be loaded and that channel binding
+# works. (see bug #17760)
+if ($supports_rsapss_certs)
+{
+ switch_server_cert($node, certfile => 'server-rsapss');
+ $node->connect_ok(
+ "$common_connstr user=ssltestuser channel_binding=require",
+ "SCRAM with SSL and channel_binding=require, server certificate uses 'rsassaPss'",
+ log_like => [
+ qr/connection authenticated: identity="ssltestuser" method=scram-sha-256/
+ ]);
+}
+done_testing();
diff --git a/src/test/ssl/t/003_sslinfo.pl b/src/test/ssl/t/003_sslinfo.pl
new file mode 100644
index 0000000..87fb18a
--- /dev/null
+++ b/src/test/ssl/t/003_sslinfo.pl
@@ -0,0 +1,165 @@
+
+# Copyright (c) 2021-2022, 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 SSL::Server;
+
+if ($ENV{with_ssl} ne 'openssl')
+{
+ plan skip_all => 'OpenSSL not supported by this build';
+}
+
+#### Some configuration
+my $ssl_server = SSL::Server->new();
+
+sub sslkey
+{
+ return $ssl_server->sslkey(@_);
+}
+
+sub switch_server_cert
+{
+ $ssl_server->switch_server_cert(@_);
+}
+
+# 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;
+
+#### 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;
+
+$ssl_server->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, certfile => 'server-revoked');
+
+# Set of default settings for SSL parameters in connection string. This
+# makes the tests protected against any defaults the environment may have
+# in ~/.postgresql/.
+my $default_ssl_connstr =
+ "sslkey=invalid sslcert=invalid sslrootcert=invalid sslcrl=invalid sslcrldir=invalid";
+
+$common_connstr =
+ "$default_ssl_connstr sslrootcert=ssl/root+server_ca.crt sslmode=require dbname=certdb hostaddr=$SERVERHOSTADDR host=localhost "
+ . "user=ssltestuser sslcert=ssl/client_ext.crt "
+ . sslkey('client_ext.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 =>
+ "$default_ssl_connstr sslrootcert=ssl/root+server_ca.crt sslmode=require "
+ . "dbname=trustdb hostaddr=$SERVERHOSTADDR user=ssltestuser host=localhost"
+);
+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 =>
+ "$default_ssl_connstr sslrootcert=ssl/root+server_ca.crt sslmode=require "
+ . "dbname=trustdb hostaddr=$SERVERHOSTADDR user=ssltestuser host=localhost"
+);
+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');
+
+done_testing();
diff --git a/src/test/ssl/t/SSL/Backend/OpenSSL.pm b/src/test/ssl/t/SSL/Backend/OpenSSL.pm
new file mode 100644
index 0000000..aed6005
--- /dev/null
+++ b/src/test/ssl/t/SSL/Backend/OpenSSL.pm
@@ -0,0 +1,229 @@
+
+# Copyright (c) 2021-2022, PostgreSQL Global Development Group
+
+=pod
+
+=head1 NAME
+
+SSL::Backend::OpenSSL
+
+=head1 SYNOPSIS
+
+ use SSL::Backend::OpenSSL;
+
+ my $backend = SSL::Backend::OpenSSL->new();
+
+ $backend->init($pgdata);
+
+=head1 DESCRIPTION
+
+SSL::Backend::OpenSSL implements the library specific parts in SSL::Server
+for a PostgreSQL cluster compiled against OpenSSL.
+
+=cut
+
+package SSL::Backend::OpenSSL;
+
+use strict;
+use warnings;
+use File::Basename;
+use File::Copy;
+
+=pod
+
+=head1 METHODS
+
+=over
+
+=item SSL::Backend::OpenSSL->new()
+
+Create a new instance of the OpenSSL backend.
+
+=cut
+
+sub new
+{
+ my ($class) = @_;
+
+ my $self = { _library => 'OpenSSL', key => {} };
+
+ bless $self, $class;
+
+ return $self;
+}
+
+=pod
+
+=item $backend->init(pgdata)
+
+Install certificates, keys and CRL files required to run the tests against an
+OpenSSL backend.
+
+=cut
+
+sub init
+{
+ my ($self, $pgdata) = @_;
+
+ # Install server certificates and keys into the cluster data directory.
+ _copy_files("ssl/server-*.crt", $pgdata);
+ _copy_files("ssl/server-*.key", $pgdata);
+ chmod(0600, glob "$pgdata/server-*.key")
+ or die "failed to change permissions on server keys: $!";
+ _copy_files("ssl/root+client_ca.crt", $pgdata);
+ _copy_files("ssl/root_ca.crt", $pgdata);
+ _copy_files("ssl/root+client.crl", $pgdata);
+ mkdir("$pgdata/root+client-crldir")
+ or die "unable to create server CRL dir $pgdata/root+client-crldir: $!";
+ _copy_files("ssl/root+client-crldir/*", "$pgdata/root+client-crldir/");
+
+ # 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 to using keys stored in a temporary path for the rest of
+ # the tests. To get the full path for inclusion in connection strings, the
+ # %key hash can be interrogated.
+ my $cert_tempdir = PostgreSQL::Test::Utils::tempdir();
+ my @keys = (
+ "client.key", "client-revoked.key",
+ "client-der.key", "client-encrypted-pem.key",
+ "client-encrypted-der.key", "client-dn.key",
+ "client_ext.key");
+ foreach my $keyfile (@keys)
+ {
+ copy("ssl/$keyfile", "$cert_tempdir/$keyfile")
+ or die
+ "couldn't copy ssl/$keyfile to $cert_tempdir/$keyfile for permissions change: $!";
+ chmod 0600, "$cert_tempdir/$keyfile"
+ or die "failed to change permissions on $cert_tempdir/$keyfile: $!";
+ $self->{key}->{$keyfile} = "$cert_tempdir/$keyfile";
+ $self->{key}->{$keyfile} =~ s!\\!/!g
+ if $PostgreSQL::Test::Utils::windows_os;
+ }
+
+ # Also make a copy of client.key explicitly world-readable in order to be
+ # able to test incorrect permissions. We can't necessarily rely on the
+ # file in the source tree having those permissions.
+ copy("ssl/client.key", "$cert_tempdir/client_wrongperms.key")
+ or die
+ "couldn't copy ssl/client_key to $cert_tempdir/client_wrongperms.key for permission change: $!";
+ chmod 0644, "$cert_tempdir/client_wrongperms.key"
+ or die
+ "failed to change permissions on $cert_tempdir/client_wrongperms.key: $!";
+ $self->{key}->{'client_wrongperms.key'} =
+ "$cert_tempdir/client_wrongperms.key";
+ $self->{key}->{'client_wrongperms.key'} =~ s!\\!/!g
+ if $PostgreSQL::Test::Utils::windows_os;
+}
+
+=pod
+
+=item $backend->get_sslkey(key)
+
+Get an 'sslkey' connection string parameter for the specified B<key> which has
+the correct path for direct inclusion in a connection string.
+
+=cut
+
+sub get_sslkey
+{
+ my ($self, $keyfile) = @_;
+
+ return " sslkey=$self->{key}->{$keyfile}";
+}
+
+=pod
+
+=item $backend->set_server_cert(params)
+
+Change the configuration to use given server cert, key and crl file(s). The
+following parameters are supported:
+
+=over
+
+=item cafile => B<value>
+
+The CA certificate file to use for the C<ssl_ca_file> GUC. If omitted it will
+default to 'root+client_ca.crt'.
+
+=item certfile => B<value>
+
+The server certificate file to use for the C<ssl_cert_file> GUC.
+
+=item keyfile => B<value>
+
+The private key file to use for the C<ssl_key_file GUC>. If omitted it will
+default to the B<certfile>.key.
+
+=item crlfile => B<value>
+
+The CRL file to use for the C<ssl_crl_file> GUC. If omitted it will default to
+'root+client.crl'.
+
+=item crldir => B<value>
+
+The CRL directory to use for the C<ssl_crl_dir> GUC. If omitted,
+C<no ssl_crl_dir> configuration parameter will be set.
+
+=back
+
+=cut
+
+sub set_server_cert
+{
+ my ($self, $params) = @_;
+
+ $params->{cafile} = 'root+client_ca' unless defined $params->{cafile};
+ $params->{crlfile} = 'root+client.crl' unless defined $params->{crlfile};
+ $params->{keyfile} = $params->{certfile}
+ unless defined $params->{keyfile};
+
+ my $sslconf =
+ "ssl_ca_file='$params->{cafile}.crt'\n"
+ . "ssl_cert_file='$params->{certfile}.crt'\n"
+ . "ssl_key_file='$params->{keyfile}.key'\n"
+ . "ssl_crl_file='$params->{crlfile}'\n";
+ $sslconf .= "ssl_crl_dir='$params->{crldir}'\n"
+ if defined $params->{crldir};
+
+ return $sslconf;
+}
+
+=pod
+
+=item $backend->get_library()
+
+Returns the name of the SSL library, in this case "OpenSSL".
+
+=cut
+
+sub get_library
+{
+ my ($self) = @_;
+
+ return $self->{_library};
+}
+
+# Internal method for copying a set of files, taking into account wildcards
+sub _copy_files
+{
+ my $orig = shift;
+ my $dest = shift;
+
+ my @orig_files = glob $orig;
+ foreach my $orig_file (@orig_files)
+ {
+ my $base_file = basename($orig_file);
+ copy($orig_file, "$dest/$base_file")
+ or die "Could not copy $orig_file to $dest";
+ }
+ return;
+}
+
+=pod
+
+=back
+
+=cut
+
+1;
diff --git a/src/test/ssl/t/SSL/Server.pm b/src/test/ssl/t/SSL/Server.pm
new file mode 100644
index 0000000..9520578
--- /dev/null
+++ b/src/test/ssl/t/SSL/Server.pm
@@ -0,0 +1,356 @@
+
+# Copyright (c) 2021-2022, PostgreSQL Global Development Group
+
+=pod
+
+=head1 NAME
+
+SSL::Server - Class for setting up SSL in a PostgreSQL Cluster
+
+=head1 SYNOPSIS
+
+ use PostgreSQL::Test::Cluster;
+ use SSL::Server;
+
+ # Create a new cluster
+ my $node = PostgreSQL::Test::Cluster->new('primary');
+
+ # Initialize and start the new cluster
+ $node->init;
+ $node->start;
+
+ # Initialize SSL Server functionality for the cluster
+ my $ssl_server = SSL::Server->new();
+
+ # Configure SSL on the newly formed cluster
+ $server->configure_test_server_for_ssl($node, '127.0.0.1', '127.0.0.1/32', 'trust');
+
+=head1 DESCRIPTION
+
+SSL::Server configures an existing test cluster, for the SSL regression tests.
+
+The server is configured as follows:
+
+=over
+
+=item * SSL enabled, with the server certificate specified by arguments to switch_server_cert function.
+
+=item * reject non-SSL connections
+
+=item * a database called trustdb that lets anyone in
+
+=item * another database called certdb that uses certificate authentication, ie. the client must present a valid certificate signed by the client CA
+
+=back
+
+The server is configured to only accept connections from localhost. If you
+want to run the client from another host, you'll have to configure that
+manually.
+
+Note: Someone running these test could have key or certificate files in their
+~/.postgresql/, which would interfere with the tests. The way to override that
+is to specify sslcert=invalid and/or sslrootcert=invalid if no actual
+certificate is used for a particular test. libpq will ignore specifications
+that name nonexisting files. (sslkey and sslcrl do not need to specified
+explicitly because an invalid sslcert or sslrootcert, respectively, causes
+those to be ignored.)
+
+The SSL::Server module presents a SSL library abstraction to the test writer,
+which in turn use modules in SSL::Backend which implements the SSL library
+specific infrastructure. Currently only OpenSSL is supported.
+
+=cut
+
+package SSL::Server;
+
+use strict;
+use warnings;
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+use Test::More;
+use SSL::Backend::OpenSSL;
+
+=pod
+
+=head1 METHODS
+
+=over
+
+=item SSL::Server->new(flavor)
+
+Create a new SSL Server object for configuring a PostgreSQL test cluster
+node for accepting SSL connections using the with B<flavor> selected SSL
+backend. If B<flavor> isn't set, the C<with_ssl> environment variable will
+be used for selecting backend. Currently only C<openssl> is supported.
+
+=cut
+
+sub new
+{
+ my $class = shift;
+ my $flavor = shift || $ENV{with_ssl};
+ die "SSL flavor not defined" unless $flavor;
+ my $self = {};
+ bless $self, $class;
+ if ($flavor =~ /\Aopenssl\z/i)
+ {
+ $self->{flavor} = 'openssl';
+ $self->{backend} = SSL::Backend::OpenSSL->new();
+ }
+ else
+ {
+ die "SSL flavor $flavor unknown";
+ }
+ return $self;
+}
+
+=pod
+
+=item sslkey(filename)
+
+Return a C<sslkey> construct for the specified key for use in a connection
+string.
+
+=cut
+
+sub sslkey
+{
+ my $self = shift;
+ my $keyfile = shift;
+ my $backend = $self->{backend};
+
+ return $backend->get_sslkey($keyfile);
+}
+
+=pod
+
+=item $server->configure_test_server_for_ssl(node, host, cidr, auth, params)
+
+Configure the cluster specified by B<node> or listening on SSL connections.
+The following databases will be created in the cluster: trustdb, certdb,
+certdb_dn, certdb_dn_re, certdb_cn, verifydb. The following users will be
+created in the cluster: ssltestuser, md5testuser, anotheruser, yetanotheruser.
+If B<< $params{password} >> is set, it will be used as password for all users
+with the password encoding B<< $params{password_enc} >> (except for md5testuser
+which always have MD5). Extensions defined in B<< @{$params{extension}} >>
+will be created in all the above created databases. B<host> is used for
+C<listen_addresses> and B<cidr> for configuring C<pg_hba.conf>.
+
+=cut
+
+sub configure_test_server_for_ssl
+{
+ my $self = shift;
+ my ($node, $serverhost, $servercidr, $authmethod, %params) = @_;
+ my $backend = $self->{backend};
+ my $pgdata = $node->data_dir;
+
+ my @databases = (
+ 'trustdb', 'certdb', 'certdb_dn', 'certdb_dn_re',
+ 'certdb_cn', 'verifydb');
+
+ # Create test users and databases
+ $node->psql('postgres', "CREATE USER ssltestuser");
+ $node->psql('postgres', "CREATE USER md5testuser");
+ $node->psql('postgres', "CREATE USER anotheruser");
+ $node->psql('postgres', "CREATE USER yetanotheruser");
+
+ foreach my $db (@databases)
+ {
+ $node->psql('postgres', "CREATE DATABASE $db");
+ }
+
+ # Update password of each user as needed.
+ if (defined($params{password}))
+ {
+ die "Password encryption must be specified when password is set"
+ unless defined($params{password_enc});
+
+ $node->psql('postgres',
+ "SET password_encryption='$params{password_enc}'; ALTER USER ssltestuser PASSWORD '$params{password}';"
+ );
+ # A special user that always has an md5-encrypted password
+ $node->psql('postgres',
+ "SET password_encryption='md5'; ALTER USER md5testuser PASSWORD '$params{password}';"
+ );
+ $node->psql('postgres',
+ "SET password_encryption='$params{password_enc}'; ALTER USER anotheruser PASSWORD '$params{password}';"
+ );
+ }
+
+ # Create any extensions requested in the setup
+ if (defined($params{extensions}))
+ {
+ foreach my $extension (@{ $params{extensions} })
+ {
+ foreach my $db (@databases)
+ {
+ $node->psql($db, "CREATE EXTENSION $extension CASCADE;");
+ }
+ }
+ }
+
+ # enable logging etc.
+ open my $conf, '>>', "$pgdata/postgresql.conf";
+ print $conf "fsync=off\n";
+ print $conf "log_connections=on\n";
+ print $conf "log_hostname=on\n";
+ print $conf "listen_addresses='$serverhost'\n";
+ print $conf "log_statement=all\n";
+
+ # enable SSL and set up server key
+ print $conf "include 'sslconfig.conf'\n";
+
+ close $conf;
+
+ # SSL configuration will be placed here
+ open my $sslconf, '>', "$pgdata/sslconfig.conf";
+ close $sslconf;
+
+ # Perform backend specific configuration
+ $backend->init($pgdata);
+
+ # Stop and restart server to load new listen_addresses.
+ $node->restart;
+
+ # Change pg_hba after restart because hostssl requires ssl=on
+ _configure_hba_for_ssl($node, $servercidr, $authmethod);
+
+ return;
+}
+
+=pod
+
+=item $server->ssl_library()
+
+Get the name of the currently used SSL backend.
+
+=cut
+
+sub ssl_library
+{
+ my $self = shift;
+ my $backend = $self->{backend};
+
+ return $backend->get_library();
+}
+
+=pod
+
+=item switch_server_cert(params)
+
+Change the configuration to use the given set of certificate, key, ca and
+CRL, and potentially reload the configuration by restarting the server so
+that the configuration takes effect. Restarting is the default, passing
+B<< $params{restart} >> => 'no' opts out of it leaving the server running.
+The following params are supported:
+
+=over
+
+=item cafile => B<value>
+
+The CA certificate to use. Implementation is SSL backend specific.
+
+=item certfile => B<value>
+
+The certificate file to use. Implementation is SSL backend specific.
+
+=item keyfile => B<value>
+
+The private key to use. Implementation is SSL backend specific.
+
+=item crlfile => B<value>
+
+The CRL file to use. Implementation is SSL backend specific.
+
+=item crldir => B<value>
+
+The CRL directory to use. Implementation is SSL backend specific.
+
+=item passphrase_cmd => B<value>
+
+The passphrase command to use. If not set, an empty passphrase command will
+be set.
+
+=item restart => B<value>
+
+If set to 'no', the server won't be restarted after updating the settings.
+If omitted, or any other value is passed, the server will be restarted before
+returning.
+
+=back
+
+=cut
+
+sub switch_server_cert
+{
+ my $self = shift;
+ my $node = shift;
+ my $backend = $self->{backend};
+ my %params = @_;
+ my $pgdata = $node->data_dir;
+
+ open my $sslconf, '>', "$pgdata/sslconfig.conf";
+ print $sslconf "ssl=on\n";
+ print $sslconf $backend->set_server_cert(\%params);
+ print $sslconf "ssl_passphrase_command='"
+ . $params{passphrase_cmd} . "'\n"
+ if defined $params{passphrase_cmd};
+ close $sslconf;
+
+ return if (defined($params{restart}) && $params{restart} eq 'no');
+
+ $node->restart;
+ return;
+}
+
+
+# Internal function for configuring pg_hba.conf for SSL connections.
+sub _configure_hba_for_ssl
+{
+ my ($node, $servercidr, $authmethod) = @_;
+ my $pgdata = $node->data_dir;
+
+ # Only accept SSL connections from $servercidr. Our tests don't depend on this
+ # but seems best to keep it as narrow as possible for security reasons.
+ #
+ # When connecting to certdb, also check the client certificate.
+ open my $hba, '>', "$pgdata/pg_hba.conf";
+ print $hba
+ "# TYPE DATABASE USER ADDRESS METHOD OPTIONS\n";
+ print $hba
+ "hostssl trustdb md5testuser $servercidr md5\n";
+ print $hba
+ "hostssl trustdb all $servercidr $authmethod\n";
+ print $hba
+ "hostssl verifydb ssltestuser $servercidr $authmethod clientcert=verify-full\n";
+ print $hba
+ "hostssl verifydb anotheruser $servercidr $authmethod clientcert=verify-full\n";
+ print $hba
+ "hostssl verifydb yetanotheruser $servercidr $authmethod clientcert=verify-ca\n";
+ print $hba
+ "hostssl certdb all $servercidr cert\n";
+ print $hba
+ "hostssl certdb_dn all $servercidr cert clientname=DN map=dn\n",
+ "hostssl certdb_dn_re all $servercidr cert clientname=DN map=dnre\n",
+ "hostssl certdb_cn all $servercidr cert clientname=CN map=cn\n";
+ close $hba;
+
+ # Also set the ident maps. Note: fields with commas must be quoted
+ open my $map, ">", "$pgdata/pg_ident.conf";
+ print $map
+ "# MAPNAME SYSTEM-USERNAME PG-USERNAME\n",
+ "dn \"CN=ssltestuser-dn,OU=Testing,OU=Engineering,O=PGDG\" ssltestuser\n",
+ "dnre \"/^.*OU=Testing,.*\$\" ssltestuser\n",
+ "cn ssltestuser-dn ssltestuser\n";
+
+ return;
+}
+
+=pod
+
+=back
+
+=cut
+
+1;