You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by ic...@apache.org on 2021/11/30 16:30:26 UTC

svn commit: r1895433 [2/2] - in /httpd/httpd/trunk/test/modules/tls: ./ htdocs/ htdocs/a.mod-tls.test/ htdocs/b.mod-tls.test/ htdocs/b.mod-tls.test/dir1/

Added: httpd/httpd/trunk/test/modules/tls/test_10_session_id.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/tls/test_10_session_id.py?rev=1895433&view=auto
==============================================================================
--- httpd/httpd/trunk/test/modules/tls/test_10_session_id.py (added)
+++ httpd/httpd/trunk/test/modules/tls/test_10_session_id.py Tue Nov 30 16:30:26 2021
@@ -0,0 +1,50 @@
+import re
+from typing import List
+
+import pytest
+
+from pyhttpd.result import ExecResult
+from .env import TlsTestEnv
+from .conf import TlsTestConf
+
+
+class TestSessionID:
+
+    @pytest.fixture(autouse=True, scope='class')
+    def _class_scope(self, env):
+        conf = TlsTestConf(env=env)
+        conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b])
+        conf.install()
+        assert env.apache_restart() == 0
+
+    def find_openssl_session_ids(self, r: ExecResult) -> List[str]:
+        ids = []
+        for line in r.stdout.splitlines():
+            m = re.match(r'^\s*Session-ID: (\S+)$', line)
+            if m:
+                ids.append(m.group(1))
+        return ids
+
+    def test_10_session_id_12(self, env):
+        r = env.openssl_client(env.domain_b, extra_args=[
+            "-reconnect", "-tls1_2"
+        ])
+        session_ids = self.find_openssl_session_ids(r)
+        assert 1 < len(session_ids), "expected several session-ids: {0}, stderr={1}".format(
+            session_ids, r.stderr
+        )
+        assert 1 == len(set(session_ids)), "sesion-ids should all be the same: {0}".format(session_ids)
+
+    @pytest.mark.skipif(True or not TlsTestEnv.openssl_supports_tls_1_3(),
+                        reason="openssl TLSv1.3 session storage test incomplete")
+    def test_10_session_id_13(self, env):
+        r = env.openssl_client(env.domain_b, extra_args=[
+            "-reconnect", "-tls1_3"
+        ])
+        # openssl -reconnect closes connection immediately after the handhshake, so
+        # the Session data in TLSv1.3 is not seen and not found in its output.
+        # FIXME: how to check session data with TLSv1.3?
+        session_ids = self.find_openssl_session_ids(r)
+        assert 0 == len(session_ids), "expected no session-ids: {0}, stderr={1}".format(
+            session_ids, r.stdout
+        )

Added: httpd/httpd/trunk/test/modules/tls/test_11_md.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/tls/test_11_md.py?rev=1895433&view=auto
==============================================================================
--- httpd/httpd/trunk/test/modules/tls/test_11_md.py (added)
+++ httpd/httpd/trunk/test/modules/tls/test_11_md.py Tue Nov 30 16:30:26 2021
@@ -0,0 +1,37 @@
+import time
+from datetime import timedelta
+
+import pytest
+
+from .conf import TlsTestConf
+
+
+class TestMD:
+
+    @pytest.fixture(autouse=True, scope='class')
+    def _class_scope(self, env):
+        conf = TlsTestConf(env=env, extras={
+            'base': "LogLevel md:trace4"
+        })
+        conf.add_md_vhosts(domains=[env.domain_a, env.domain_b])
+        conf.install()
+        assert env.apache_restart() == 0
+
+    def test_11_get_a(self, env):
+        # do we see the correct json for the domain_a?
+        data = env.tls_get_json(env.domain_a, "/index.json")
+        assert data == {'domain': env.domain_a}
+
+    def test_11_get_b(self, env):
+        # do we see the correct json for the domain_a?
+        data = env.tls_get_json(env.domain_b, "/index.json")
+        assert data == {'domain': env.domain_b}
+
+    def test_11_get_base(self, env):
+        # give the base server domain_a and lookup its index.json
+        conf = TlsTestConf(env=env)
+        conf.add_md_base(domain=env.domain_a)
+        conf.install()
+        assert env.apache_restart() == 0
+        data = env.tls_get_json(env.domain_a, "/index.json")
+        assert data == {'domain': 'localhost'}

Added: httpd/httpd/trunk/test/modules/tls/test_12_cauth.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/tls/test_12_cauth.py?rev=1895433&view=auto
==============================================================================
--- httpd/httpd/trunk/test/modules/tls/test_12_cauth.py (added)
+++ httpd/httpd/trunk/test/modules/tls/test_12_cauth.py Tue Nov 30 16:30:26 2021
@@ -0,0 +1,235 @@
+import os
+from datetime import timedelta
+from typing import Optional
+
+import pytest
+
+from pyhttpd.certs import Credentials
+from .conf import TlsTestConf
+
+
+@pytest.fixture
+def clients_x(env):
+    return env.ca.get_first("clientsX")
+
+
+@pytest.fixture
+def clients_y(env):
+    return env.ca.get_first("clientsY")
+
+
+@pytest.fixture
+def cax_file(clients_x):
+    return os.path.join(os.path.dirname(clients_x.cert_file), "clientX-ca.pem")
+
+
+@pytest.mark.skip(reason="client certs disabled")
+class TestTLS:
+
+    @pytest.fixture(autouse=True, scope='class')
+    def _class_scope(self, env, clients_x, cax_file):
+        with open(cax_file, 'w') as fd:
+            fd.write("".join(open(clients_x.cert_file).readlines()))
+            fd.write("".join(open(env.ca.cert_file).readlines()))
+
+    @pytest.fixture(autouse=True, scope='function')
+    def _function_scope(self, env):
+        if env.is_live(timeout=timedelta(milliseconds=100)):
+            assert env.apache_stop() == 0
+
+    def get_ssl_var(self, env, domain: str, cert: Optional[Credentials], name: str):
+        r = env.tls_get(domain, f"/vars.py?name={name}", options=[
+            "--cert", cert.cert_file
+        ] if cert else [])
+        assert r.exit_code == 0, r.stderr
+        assert r.json, r.stderr + r.stdout
+        return r.json[name] if name in r.json else None
+
+    def test_12_set_ca_non_existing(self, env):
+        conf = TlsTestConf(env=env, extras={
+            env.domain_a: "TLSClientCA xxx"
+        })
+        conf.add_md_vhosts(domains=[env.domain_a, env.domain_b])
+        conf.install()
+        assert env.apache_restart() == 1
+
+    def test_12_set_ca_existing(self, env, cax_file):
+        conf = TlsTestConf(env=env, extras={
+            env.domain_a: f"TLSClientCA {cax_file}"
+        })
+        conf.add_md_vhosts(domains=[env.domain_a, env.domain_b])
+        conf.install()
+        assert env.apache_restart() == 0
+
+    def test_12_set_auth_no_ca(self, env):
+        conf = TlsTestConf(env=env, extras={
+            env.domain_a: "TLSClientCertificate required"
+        })
+        conf.add_md_vhosts(domains=[env.domain_a, env.domain_b])
+        conf.install()
+        # will fail bc lacking clien CA
+        assert env.apache_restart() == 1
+
+    def test_12_auth_option_std(self, env, cax_file, clients_x):
+        conf = TlsTestConf(env=env, extras={
+            env.domain_b: [
+                f"TLSClientCertificate required",
+                f"TLSClientCA {cax_file}",
+                "# TODO: TLSUserName SSL_CLIENT_S_DN_CN",
+                "TLSOptions +StdEnvVars",
+            ]
+        })
+        conf.add_md_vhosts(domains=[env.domain_b])
+        conf.install()
+        assert env.apache_restart() == 0
+        # should be denied
+        r = env.tls_get(domain=env.domain_b, paths="/index.json")
+        assert r.exit_code != 0, r.stdout
+        # should work
+        ccert = clients_x.get_first("user1")
+        data = env.tls_get_json(env.domain_b, "/index.json", options=[
+            "--cert", ccert.cert_file
+        ])
+        assert data == {'domain': env.domain_b}
+        r = env.tls_get(env.domain_b, "/vars.py?name=SSL_CLIENT_S_DN_CN")
+        assert r.exit_code != 0, "should have been prevented"
+        val = self.get_ssl_var(env, env.domain_b, ccert, "SSL_CLIENT_S_DN_CN")
+        assert val == 'Not Implemented'
+        # TODO
+        # val = self.get_ssl_var(env, env.domain_b, ccert, "REMOTE_USER")
+        # assert val == 'Not Implemented'
+        # not set on StdEnvVars, needs option ExportCertData
+        val = self.get_ssl_var(env, env.domain_b, ccert, "SSL_CLIENT_CERT")
+        assert val == ""
+
+    def test_12_auth_option_cert(self, env, test_ca, cax_file, clients_x):
+        conf = TlsTestConf(env=env, extras={
+            env.domain_b: [
+                "TLSClientCertificate required",
+                f"TLSClientCA {cax_file}",
+                "TLSOptions Defaults +ExportCertData",
+            ]
+        })
+        conf.add_md_vhosts(domains=[env.domain_b])
+        conf.install()
+        assert env.apache_restart() == 0
+        ccert = clients_x.get_first("user1")
+        val = self.get_ssl_var(env, env.domain_b, ccert, "SSL_CLIENT_CERT")
+        assert val == ccert.cert_pem.decode()
+        # no chain should be present
+        val = self.get_ssl_var(env, env.domain_b, ccert, "SSL_CLIENT_CHAIN_0")
+        assert val == ''
+        val = self.get_ssl_var(env, env.domain_b, ccert, "SSL_SERVER_CERT")
+        assert val
+        server_certs = test_ca.get_credentials_for_name(env.domain_b)
+        assert val in [c.cert_pem.decode() for c in server_certs]
+
+    def test_12_auth_ssl_optional(self, env, cax_file, clients_x):
+        domain = env.domain_b
+        conf = TlsTestConf(env=env, extras={
+            domain: [
+                "SSLVerifyClient optional",
+                "SSLVerifyDepth 2",
+                "SSLOptions +StdEnvVars +ExportCertData",
+                f"SSLCACertificateFile {cax_file}",
+                "SSLUserName SSL_CLIENT_S_DN",
+            ]
+        })
+        conf.add_ssl_vhosts(domains=[domain])
+        conf.install()
+        assert env.apache_restart() == 0
+        # should work either way
+        data = env.tls_get_json(domain, "/index.json")
+        assert data == {'domain': domain}
+        # no client cert given, we expect the server variable to be empty
+        val = self.get_ssl_var(env, env.domain_b, None, "SSL_CLIENT_S_DN_CN")
+        assert val == ''
+        ccert = clients_x.get_first("user1")
+        data = env.tls_get_json(domain, "/index.json", options=[
+            "--cert", ccert.cert_file
+        ])
+        assert data == {'domain': domain}
+        val = self.get_ssl_var(env, env.domain_b, ccert, "SSL_CLIENT_S_DN_CN")
+        assert val == 'user1'
+        val = self.get_ssl_var(env, env.domain_b, ccert, "SSL_CLIENT_S_DN")
+        assert val == 'O=abetterinternet-mod_tls,OU=clientsX,CN=user1'
+        val = self.get_ssl_var(env, env.domain_b, ccert, "REMOTE_USER")
+        assert val == 'O=abetterinternet-mod_tls,OU=clientsX,CN=user1'
+        val = self.get_ssl_var(env, env.domain_b, ccert, "SSL_CLIENT_I_DN")
+        assert val == 'O=abetterinternet-mod_tls,OU=clientsX'
+        val = self.get_ssl_var(env, env.domain_b, ccert, "SSL_CLIENT_I_DN_CN")
+        assert val == ''
+        val = self.get_ssl_var(env, env.domain_b, ccert, "SSL_CLIENT_I_DN_OU")
+        assert val == 'clientsX'
+        val = self.get_ssl_var(env, env.domain_b, ccert, "SSL_CLIENT_CERT")
+        assert val == ccert.cert_pem.decode()
+
+    def test_12_auth_optional(self, env, cax_file, clients_x):
+        domain = env.domain_b
+        conf = TlsTestConf(env=env, extras={
+            domain: [
+                "TLSClientCertificate optional",
+                f"TLSClientCA {cax_file}",
+            ]
+        })
+        conf.add_md_vhosts(domains=[domain])
+        conf.install()
+        assert env.apache_restart() == 0
+        # should work either way
+        data = env.tls_get_json(domain, "/index.json")
+        assert data == {'domain': domain}
+        # no client cert given, we expect the server variable to be empty
+        r = env.tls_get(domain, "/vars.py?name=SSL_CLIENT_S_DN_CN")
+        assert r.exit_code == 0, r.stderr
+        assert r.json == {
+            'SSL_CLIENT_S_DN_CN': '',
+        }, r.stdout
+        data = env.tls_get_json(domain, "/index.json", options=[
+            "--cert", clients_x.get_first("user1").cert_file
+        ])
+        assert data == {'domain': domain}
+        r = env.tls_get(domain, "/vars.py?name=SSL_CLIENT_S_DN_CN", options=[
+            "--cert", clients_x.get_first("user1").cert_file
+        ])
+        # with client cert, we expect the server variable to show? Do we?
+        assert r.exit_code == 0, r.stderr
+        assert r.json == {
+            'SSL_CLIENT_S_DN_CN': 'Not Implemented',
+        }, r.stdout
+
+    def test_12_auth_expired(self, env, cax_file, clients_x):
+        conf = TlsTestConf(env=env, extras={
+            env.domain_b: [
+                "TLSClientCertificate required",
+                f"TLSClientCA {cax_file}",
+            ]
+        })
+        conf.add_md_vhosts(domains=[env.domain_b])
+        conf.install()
+        assert env.apache_restart() == 0
+        # should not work
+        r = env.tls_get(domain=env.domain_b, paths="/index.json", options=[
+            "--cert", clients_x.get_first("user_expired").cert_file
+        ])
+        assert r.exit_code != 0
+
+    def test_12_auth_other_ca(self, env, cax_file, clients_y):
+        conf = TlsTestConf(env=env, extras={
+            env.domain_b: [
+                "TLSClientCertificate required",
+                f"TLSClientCA {cax_file}",
+            ]
+        })
+        conf.add_md_vhosts(domains=[env.domain_b])
+        conf.install()
+        assert env.apache_restart() == 0
+        # should not work
+        r = env.tls_get(domain=env.domain_b, paths="/index.json", options=[
+            "--cert", clients_y.get_first("user1").cert_file
+        ])
+        assert r.exit_code != 0
+        # This will work, as the CA root is present in the CA file
+        r = env.tls_get(domain=env.domain_b, paths="/index.json", options=[
+            "--cert", env.ca.get_first("user1").cert_file
+        ])
+        assert r.exit_code == 0

Added: httpd/httpd/trunk/test/modules/tls/test_13_proxy.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/tls/test_13_proxy.py?rev=1895433&view=auto
==============================================================================
--- httpd/httpd/trunk/test/modules/tls/test_13_proxy.py (added)
+++ httpd/httpd/trunk/test/modules/tls/test_13_proxy.py Tue Nov 30 16:30:26 2021
@@ -0,0 +1,40 @@
+from datetime import timedelta
+
+import pytest
+
+from .conf import TlsTestConf
+
+
+class TestProxy:
+
+    @pytest.fixture(autouse=True, scope='class')
+    def _class_scope(self, env):
+        conf = TlsTestConf(env=env, extras={
+            'base': "LogLevel proxy:trace1 proxy_http:trace1 ssl:trace1",
+            env.domain_b: [
+                "ProxyPreserveHost on",
+                f'ProxyPass "/proxy/" "http://127.0.0.1:{env.http_port}/"',
+                f'ProxyPassReverse "/proxy/" "http://{env.domain_b}:{env.http_port}"',
+            ]
+        })
+        # add vhosts a+b and a ssl proxy from a to b
+        conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b])
+        conf.install()
+        assert env.apache_restart() == 0
+
+    def test_13_proxy_http_get(self, env):
+        data = env.tls_get_json(env.domain_b, "/proxy/index.json")
+        assert data == {'domain': env.domain_b}
+
+    @pytest.mark.parametrize("name, value", [
+        ("SERVER_NAME", "b.mod-tls.test"),
+        ("SSL_SESSION_RESUMED", ""),
+        ("SSL_SECURE_RENEG", ""),
+        ("SSL_COMPRESS_METHOD", ""),
+        ("SSL_CIPHER_EXPORT", ""),
+        ("SSL_CLIENT_VERIFY", ""),
+    ])
+    def test_13_proxy_http_vars(self, env, name: str, value: str):
+        r = env.tls_get(env.domain_b, f"/proxy/vars.py?name={name}")
+        assert r.exit_code == 0, r.stderr
+        assert r.json == {name: value}, r.stdout

Added: httpd/httpd/trunk/test/modules/tls/test_14_proxy_ssl.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/tls/test_14_proxy_ssl.py?rev=1895433&view=auto
==============================================================================
--- httpd/httpd/trunk/test/modules/tls/test_14_proxy_ssl.py (added)
+++ httpd/httpd/trunk/test/modules/tls/test_14_proxy_ssl.py Tue Nov 30 16:30:26 2021
@@ -0,0 +1,78 @@
+import re
+import pytest
+
+from .conf import TlsTestConf
+
+
+class TestProxySSL:
+
+    @pytest.fixture(autouse=True, scope='class')
+    def _class_scope(self, env):
+        # add vhosts a+b and a ssl proxy from a to b
+        conf = TlsTestConf(env=env, extras={
+            'base': [
+                "LogLevel proxy:trace1 proxy_http:trace1 ssl:trace1 proxy_http2:trace1",
+                f"<Proxy https://127.0.0.1:{env.https_port}/>",
+                "    SSLProxyEngine on",
+                "    SSLProxyVerify require",
+                f"    SSLProxyCACertificateFile {env.ca.cert_file}",
+                "  ProxyPreserveHost on",
+                "</Proxy>",
+                f"<Proxy https://localhost:{env.https_port}/>",
+                "    ProxyPreserveHost on",
+                "</Proxy>",
+                f"<Proxy h2://127.0.0.1:{env.https_port}/>",
+                "    SSLProxyEngine on",
+                "    SSLProxyVerify require",
+                f"    SSLProxyCACertificateFile {env.ca.cert_file}",
+                "    ProxyPreserveHost on",
+                "</Proxy>",
+                ],
+            env.domain_b: [
+                "Protocols h2 http/1.1",
+                f'ProxyPass /proxy-ssl/ https://127.0.0.1:{env.https_port}/',
+                f'ProxyPass /proxy-local/ https://localhost:{env.https_port}/',
+                f'ProxyPass /proxy-h2-ssl/ h2://127.0.0.1:{env.https_port}/',
+                "TLSOptions +StdEnvVars",
+            ],
+        })
+        conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b])
+        conf.install()
+        assert env.apache_restart() == 0
+
+    def test_14_proxy_ssl_get(self, env):
+        data = env.tls_get_json(env.domain_b, "/proxy-ssl/index.json")
+        assert data == {'domain': env.domain_b}
+
+    def test_14_proxy_ssl_get_local(self, env):
+        # does not work, since SSLProxy* not configured
+        data = env.tls_get_json(env.domain_b, "/proxy-local/index.json")
+        assert data is None
+
+    def test_14_proxy_ssl_h2_get(self, env):
+        r = env.tls_get(env.domain_b, "/proxy-h2-ssl/index.json")
+        assert r.exit_code == 0
+        assert r.json == {'domain': env.domain_b}
+
+    @pytest.mark.parametrize("name, value", [
+        ("SERVER_NAME", "b.mod-tls.test"),
+        ("SSL_SESSION_RESUMED", "Initial"),
+        ("SSL_SECURE_RENEG", "false"),
+        ("SSL_COMPRESS_METHOD", "NULL"),
+        ("SSL_CIPHER_EXPORT", "false"),
+        ("SSL_CLIENT_VERIFY", "NONE"),
+    ])
+    def test_14_proxy_ssl_vars_const(self, env, name: str, value: str):
+        r = env.tls_get(env.domain_b, f"/proxy-ssl/vars.py?name={name}")
+        assert r.exit_code == 0, r.stderr
+        assert r.json == {name: value}, r.stdout
+
+    @pytest.mark.parametrize("name, pattern", [
+        ("SSL_VERSION_INTERFACE", r'mod_tls/\d+\.\d+\.\d+'),
+        ("SSL_VERSION_LIBRARY", r'rustls-ffi/\d+\.\d+\.\d+/rustls/\d+\.\d+\.\d+'),
+    ])
+    def test_14_proxy_ssl_vars_match(self, env, name: str, pattern: str):
+        r = env.tls_get(env.domain_b, f"/proxy-ssl/vars.py?name={name}")
+        assert r.exit_code == 0, r.stderr
+        assert name in r.json
+        assert re.match(pattern, r.json[name]), r.json

Added: httpd/httpd/trunk/test/modules/tls/test_15_proxy_tls.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/tls/test_15_proxy_tls.py?rev=1895433&view=auto
==============================================================================
--- httpd/httpd/trunk/test/modules/tls/test_15_proxy_tls.py (added)
+++ httpd/httpd/trunk/test/modules/tls/test_15_proxy_tls.py Tue Nov 30 16:30:26 2021
@@ -0,0 +1,89 @@
+import re
+from datetime import timedelta
+
+import pytest
+
+from .conf import TlsTestConf
+
+
+class TestProxyTLS:
+
+    @pytest.fixture(autouse=True, scope='class')
+    def _class_scope(self, env):
+        # add vhosts a+b and a ssl proxy from a to b
+        conf = TlsTestConf(env=env, extras={
+            'base': [
+                "LogLevel proxy:trace1 proxy_http:trace1 proxy_http2:trace2 http2:trace2 cgid:trace4",
+                "TLSProxyProtocol TLSv1.3+",
+                f"<Proxy https://127.0.0.1:{env.https_port}/>",
+                "    TLSProxyEngine on",
+                f"    TLSProxyCA {env.ca.cert_file}",
+                "    TLSProxyProtocol TLSv1.2+",
+                "    TLSProxyCiphersPrefer TLS13_AES_256_GCM_SHA384",
+                "    TLSProxyCiphersSuppress TLS13_AES_128_GCM_SHA256",
+                "    ProxyPreserveHost on",
+                "</Proxy>",
+                f"<Proxy https://localhost:{env.https_port}/>",
+                "    ProxyPreserveHost on",
+                "</Proxy>",
+                f"<Proxy h2://127.0.0.1:{env.https_port}/>",
+                "    TLSProxyEngine on",
+                f"    TLSProxyCA {env.ca.cert_file}",
+                "    TLSProxyCiphersSuppress TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256",
+                "    ProxyPreserveHost on",
+                "</Proxy>",
+            ],
+            env.domain_b: [
+                "Protocols h2 http/1.1",
+                f"ProxyPass /proxy-tls/ https://127.0.0.1:{env.https_port}/",
+                f"ProxyPass /proxy-local/ https://localhost:{env.https_port}/",
+                f"ProxyPass /proxy-h2-tls/ h2://127.0.0.1:{env.https_port}/",
+                "TLSOptions +StdEnvVars",
+            ],
+        })
+        conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b])
+        conf.install()
+        assert env.apache_restart() == 0
+
+    def test_15_proxy_tls_get(self, env):
+        data = env.tls_get_json(env.domain_b, "/proxy-tls/index.json")
+        assert data == {'domain': env.domain_b}
+
+    def test_15_proxy_tls_get_local(self, env):
+        # does not work, since SSLProxy* not configured
+        data = env.tls_get_json(env.domain_b, "/proxy-local/index.json")
+        assert data is None
+
+    def test_15_proxy_tls_h2_get(self, env):
+        r = env.tls_get(env.domain_b, "/proxy-h2-tls/index.json")
+        assert r.exit_code == 0
+        assert r.json == {'domain': env.domain_b}, f"{r.stdout}"
+
+    @pytest.mark.parametrize("name, value", [
+        ("SERVER_NAME", "b.mod-tls.test"),
+        ("SSL_PROTOCOL", "TLSv1.3"),
+        ("SSL_CIPHER", "TLS_AES_256_GCM_SHA384"),
+        ("SSL_SESSION_RESUMED", "Initial"),
+        ("SSL_SECURE_RENEG", "false"),
+        ("SSL_COMPRESS_METHOD", "NULL"),
+        ("SSL_CIPHER_EXPORT", "false"),
+        ("SSL_CLIENT_VERIFY", "NONE"),
+    ])
+    def test_15_proxy_tls_h1_vars(self, env, name: str, value: str):
+        r = env.tls_get(env.domain_b, f"/proxy-tls/vars.py?name={name}")
+        assert r.exit_code == 0, r.stderr
+        assert r.json == {name: value}, r.stdout
+
+    @pytest.mark.parametrize("name, value", [
+        ("SERVER_NAME", "b.mod-tls.test"),
+        ("SERVER_NAME", "b.mod-tls.test"),
+        ("SERVER_NAME", "b.mod-tls.test"),
+        ("SERVER_NAME", "b.mod-tls.test"),
+        ("SSL_PROTOCOL", "TLSv1.3"),
+        ("SSL_CIPHER", "TLS_CHACHA20_POLY1305_SHA256"),
+        ("SSL_SESSION_RESUMED", "Initial"),
+    ])
+    def test_15_proxy_tls_h2_vars(self, env, name: str, value: str):
+        r = env.tls_get(env.domain_b, f"/proxy-h2-tls/vars.py?name={name}")
+        assert r.exit_code == 0, r.stderr
+        assert r.json == {name: value}, r.stdout

Added: httpd/httpd/trunk/test/modules/tls/test_16_proxy_mixed.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/tls/test_16_proxy_mixed.py?rev=1895433&view=auto
==============================================================================
--- httpd/httpd/trunk/test/modules/tls/test_16_proxy_mixed.py (added)
+++ httpd/httpd/trunk/test/modules/tls/test_16_proxy_mixed.py Tue Nov 30 16:30:26 2021
@@ -0,0 +1,43 @@
+import pytest
+
+from .conf import TlsTestConf
+
+
+class TestProxyMixed:
+
+    @pytest.fixture(autouse=True, scope='class')
+    def _class_scope(self, env):
+        conf = TlsTestConf(env=env, extras={
+            'base': [
+                "LogLevel proxy:trace1 proxy_http:trace1 ssl:trace1 proxy_http2:trace1",
+                "ProxyPreserveHost on",
+            ],
+            env.domain_a: [
+                "Protocols h2 http/1.1",
+                "TLSProxyEngine on",
+                f"TLSProxyCA {env.ca.cert_file}",
+                "<Location /proxy-tls/>",
+                f"    ProxyPass h2://127.0.0.1:{env.https_port}/",
+                "</Location>",
+            ],
+            env.domain_b: [
+                "SSLProxyEngine on",
+                "SSLProxyVerify require",
+                f"SSLProxyCACertificateFile {env.ca.cert_file}",
+                "<Location /proxy-ssl/>",
+                f"    ProxyPass https://127.0.0.1:{env.https_port}/",
+                "</Location>",
+            ],
+        })
+        # add vhosts a+b and a ssl proxy from a to b
+        conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b])
+        conf.install()
+        assert env.apache_restart() == 0
+
+    def test_16_proxy_mixed_ssl_get(self, env):
+        data = env.tls_get_json(env.domain_b, "/proxy-ssl/index.json")
+        assert data == {'domain': env.domain_b}
+
+    def test_16_proxy_mixed_tls_get(self, env):
+        data = env.tls_get_json(env.domain_a, "/proxy-tls/index.json")
+        assert data == {'domain': env.domain_a}

Added: httpd/httpd/trunk/test/modules/tls/test_17_proxy_machine_cert.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/tls/test_17_proxy_machine_cert.py?rev=1895433&view=auto
==============================================================================
--- httpd/httpd/trunk/test/modules/tls/test_17_proxy_machine_cert.py (added)
+++ httpd/httpd/trunk/test/modules/tls/test_17_proxy_machine_cert.py Tue Nov 30 16:30:26 2021
@@ -0,0 +1,69 @@
+import os
+
+import pytest
+
+from .conf import TlsTestConf
+
+
+class TestProxyMachineCert:
+
+    @pytest.fixture(autouse=True, scope='class')
+    def clients_x(cls, env):
+        return env.ca.get_first("clientsX")
+
+    @pytest.fixture(autouse=True, scope='class')
+    def clients_y(cls, env):
+        return env.ca.get_first("clientsY")
+
+    @pytest.fixture(autouse=True, scope='class')
+    def cax_file(cls, clients_x):
+        return os.path.join(os.path.dirname(clients_x.cert_file), "clientsX-ca.pem")
+
+    @pytest.fixture(autouse=True, scope='class')
+    def _class_scope(cls, env, cax_file, clients_x):
+        # add vhosts a(tls)+b(ssl, port2) and a ssl proxy from a to b with a machine cert
+        # host b requires a client certificate
+        conf = TlsTestConf(env=env, extras={
+            'base': [
+                "LogLevel proxy:trace1 proxy_http:trace1 ssl:trace4 proxy_http2:trace1",
+                "ProxyPreserveHost on",
+                f"Listen {env.proxy_port}",
+            ],
+        })
+        conf.start_tls_vhost(domains=[env.domain_a], port=env.https_port)
+        conf.add([
+            "Protocols h2 http/1.1",
+            "TLSProxyEngine on",
+            f"TLSProxyCA {env.ca.cert_file}",
+            f"TLSProxyMachineCertificate {clients_x.get_first('user1').cert_file}",
+            "<Location /proxy-tls/>",
+            f"    ProxyPass https://127.0.0.1:{env.proxy_port}/",
+            "</Location>",
+        ])
+        conf.end_tls_vhost()
+        conf.start_vhost(domains=[env.domain_a], port=env.proxy_port,
+                         doc_root=f"htdocs/{env.domain_a}", with_ssl=True)
+        conf.add([
+            "SSLVerifyClient require",
+            "SSLVerifyDepth 2",
+            "SSLOptions +StdEnvVars +ExportCertData",
+            f"SSLCACertificateFile {cax_file}",
+            "SSLUserName SSL_CLIENT_S_DN_CN"
+        ])
+        conf.end_vhost()
+        conf.install()
+        assert env.apache_restart() == 0
+
+    def test_17_proxy_machine_cert_get_a(self, env):
+        data = env.tls_get_json(env.domain_a, "/proxy-tls/index.json")
+        assert data == {'domain': env.domain_a}
+
+    @pytest.mark.parametrize("name, value", [
+        ("SERVER_NAME", "a.mod-tls.test"),
+        ("SSL_CLIENT_VERIFY", "SUCCESS"),
+        ("REMOTE_USER", "user1"),
+    ])
+    def test_17_proxy_machine_cert_vars(self, env, name: str, value: str):
+        r = env.tls_get(env.domain_a, f"/proxy-tls/vars.py?name={name}")
+        assert r.exit_code == 0, r.stderr
+        assert r.json == {name: value}, r.stdout