import re import pytest from .env import H2Conf, H2TestEnv @pytest.mark.skipif(condition=H2TestEnv.is_unsupported, reason="mod_http2 not supported here") @pytest.mark.skipif(H2TestEnv.get_ssl_module() != "mod_ssl", reason="only for mod_ssl") class TestSslRenegotiation: @pytest.fixture(autouse=True, scope='class') def _class_scope(self, env): domain = f"ssl.{env.http_tld}" conf = H2Conf(env, extras={ 'base': [ "SSLCipherSuite ECDHE-RSA-AES256-GCM-SHA384", f"", " Require all granted", " SSLVerifyClient require", " SSLVerifyDepth 0", "" ], domain: [ "Protocols h2 http/1.1", "", " SSLCipherSuite ECDHE-RSA-CHACHA20-POLY1305", "", "", " SSLCipherSuite ECDHE-RSA-CHACHA20-POLY1305", " ErrorDocument 403 /forbidden.html", "", "", " SSLVerifyClient require", "", f"", " SSLRequireSSL", "", f"", " Require ssl", "", ]}) conf.add_vhost(domains=[domain], port=env.https_port, doc_root=f"{env.server_dir}/htdocs") conf.install() # the dir needs to exists for the configuration to have effect env.mkpath("%s/htdocs/ssl-client-verify" % env.server_dir) env.mkpath("%s/htdocs/renegotiate/cipher" % env.server_dir) env.mkpath("%s/htdocs/sslrequire" % env.server_dir) env.mkpath("%s/htdocs/requiressl" % env.server_dir) assert env.apache_restart() == 0 # access a resource with SSL renegotiation, using HTTP/1.1 def test_h2_101_01(self, env): url = env.mkurl("https", "ssl", "/renegotiate/cipher/") r = env.curl_get(url, options=["-v", "--http1.1", "--tlsv1.2", "--tls-max", "1.2"]) assert 0 == r.exit_code, f"{r}" assert r.response assert 403 == r.response["status"] # env.httpd_error_log.ignore_recent( lognos = [ "AH01276" # No matching DirectoryIndex found ] ) # try to renegotiate the cipher, should fail with correct code def test_h2_101_02(self, env): if not (env.curl_is_at_least('8.2.0') or env.curl_is_less_than('8.1.0')): pytest.skip("need curl != 8.1.x version") url = env.mkurl("https", "ssl", "/renegotiate/cipher/") r = env.curl_get(url, options=[ "-vvv", "--tlsv1.2", "--tls-max", "1.2", "--ciphers", "ECDHE-RSA-AES256-GCM-SHA384" ]) assert 0 != r.exit_code assert not r.response assert re.search(r'HTTP_1_1_REQUIRED \(err 13\)', r.stderr) # env.httpd_error_log.ignore_recent( lognos = [ "AH02261" # Re-negotiation handshake failed ], matches = [ r'.*:tls_post_process_client_hello:.*', r'.*SSL Library Error:.*:SSL routines::no shared cipher.*' ] ) # try to renegotiate a client certificate from Location # needs to fail with correct code def test_h2_101_03(self, env): if not (env.curl_is_at_least('8.2.0') or env.curl_is_less_than('8.1.0')): pytest.skip("need curl != 8.1.x version") url = env.mkurl("https", "ssl", "/renegotiate/verify/") r = env.curl_get(url, options=["-vvv", "--tlsv1.2", "--tls-max", "1.2"]) assert 0 != r.exit_code assert not r.response assert re.search(r'HTTP_1_1_REQUIRED \(err 13\)', r.stderr) # env.httpd_error_log.ignore_recent( lognos = [ "AH02261" # Re-negotiation handshake failed ], matches = [ r'.*:tls_process_client_certificate:.*', r'.*SSL Library Error:.*:SSL routines::peer did not return a certificate.*' ] ) # try to renegotiate a client certificate from Directory # needs to fail with correct code def test_h2_101_04(self, env): if not (env.curl_is_at_least('8.2.0') or env.curl_is_less_than('8.1.0')): pytest.skip("need curl != 8.1.x version") url = env.mkurl("https", "ssl", "/ssl-client-verify/index.html") r = env.curl_get(url, options=["-vvv", "--tlsv1.2", "--tls-max", "1.2"]) assert 0 != r.exit_code, f"{r}" assert not r.response assert re.search(r'HTTP_1_1_REQUIRED \(err 13\)', r.stderr) # env.httpd_error_log.ignore_recent( lognos = [ "AH02261" # Re-negotiation handshake failed ], matches = [ r'.*:tls_process_client_certificate:.*', r'.*SSL Library Error:.*:SSL routines::peer did not return a certificate.*' ] ) # make 10 requests on the same connection, none should produce a status code # reported by erki@example.ee def test_h2_101_05(self, env): r = env.run([env.h2load, "-n", "10", "-c", "1", "-m", "1", "-vvvv", f"{env.https_base_url}/ssl-client-verify/index.html"]) assert 0 == r.exit_code r = env.h2load_status(r) assert 10 == r.results["h2load"]["requests"]["total"] assert 10 == r.results["h2load"]["requests"]["started"] assert 10 == r.results["h2load"]["requests"]["done"] assert 0 == r.results["h2load"]["requests"]["succeeded"] assert 0 == r.results["h2load"]["status"]["2xx"] assert 0 == r.results["h2load"]["status"]["3xx"] assert 0 == r.results["h2load"]["status"]["4xx"] assert 0 == r.results["h2load"]["status"]["5xx"] # Check that "SSLRequireSSL" works on h2 connections # See def test_h2_101_10a(self, env): url = env.mkurl("https", "ssl", "/sslrequire/index.html") r = env.curl_get(url) assert 0 == r.exit_code assert r.response assert 404 == r.response["status"] # Check that "require ssl" works on h2 connections # See def test_h2_101_10b(self, env): url = env.mkurl("https", "ssl", "/requiressl/index.html") r = env.curl_get(url) assert 0 == r.exit_code assert r.response assert 404 == r.response["status"] # Check that status works with ErrorDoc, see pull #174, fixes #172 def test_h2_101_11(self, env): if not (env.curl_is_at_least('8.2.0') or env.curl_is_less_than('8.1.0')): pytest.skip("need curl != 8.1.x version") url = env.mkurl("https", "ssl", "/renegotiate/err-doc-cipher") r = env.curl_get(url, options=[ "-vvv", "--tlsv1.2", "--tls-max", "1.2", "--ciphers", "ECDHE-RSA-AES256-GCM-SHA384" ]) assert 0 != r.exit_code assert not r.response assert re.search(r'HTTP_1_1_REQUIRED \(err 13\)', r.stderr) # env.httpd_error_log.ignore_recent( lognos = [ "AH02261" # Re-negotiation handshake failed ], matches = [ r'.*:tls_post_process_client_hello:.*', r'.*SSL Library Error:.*:SSL routines::no shared cipher.*' ] )