|
|
import os
|
|
|
|
|
|
import pytest
|
|
|
import defusedxml.ElementTree as ElementTree
|
|
|
|
|
|
import testinfra.utils.ansible_runner
|
|
|
|
|
|
from tls_ciphers import ALL_CIPHERS
|
|
|
|
|
|
|
|
|
testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
|
|
|
os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('parameters-mandatory')
|
|
|
|
|
|
|
|
|
def test_tls_version(host):
|
|
|
def test_tls_version_and_ciphers(host):
|
|
|
"""
|
|
|
Tests if only the configured TLS protocol versions are allowed by
|
|
|
the server.
|
|
|
Tests if the correct TLS version and ciphers have been enabled.
|
|
|
"""
|
|
|
|
|
|
old_tls_versions_disabled = host.run("echo 'Q' | openssl s_client -no_tls1_2 -connect parameters-mandatory:443")
|
|
|
|
|
|
# Avoid false negatives by ensuring the client had actually
|
|
|
# established the TCP connection.
|
|
|
assert "CONNECTED" in old_tls_versions_disabled.stdout
|
|
|
assert old_tls_versions_disabled.rc != 0
|
|
|
|
|
|
|
|
|
ENABLED_CIPHERS = [
|
|
|
"DHE-RSA-AES128-GCM-SHA256",
|
|
|
"DHE-RSA-AES256-GCM-SHA384",
|
|
|
"DHE-RSA-CHACHA20-POLY1305",
|
|
|
"ECDHE-RSA-AES128-GCM-SHA256",
|
|
|
"ECDHE-RSA-AES256-GCM-SHA384",
|
|
|
"ECDHE-RSA-CHACHA20-POLY1305",
|
|
|
]
|
|
|
expected_tls_versions = ["TLSv1.2"]
|
|
|
|
|
|
DISABLED_CIPHERS = sorted(list(set(ALL_CIPHERS)-set(ENABLED_CIPHERS)))
|
|
|
expected_tls_ciphers = [
|
|
|
"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
|
|
|
"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",
|
|
|
"TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
|
|
|
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
|
|
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
|
|
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
|
|
|
]
|
|
|
|
|
|
# Run the nmap scanner against the LDAP server, and fetch the
|
|
|
# results.
|
|
|
nmap = host.run("nmap -sV --script ssl-enum-ciphers -p 443 localhost -oX /tmp/report.xml")
|
|
|
assert nmap.rc == 0
|
|
|
report_content = host.file('/tmp/report.xml').content_string
|
|
|
|
|
|
@pytest.mark.parametrize("cipher", ENABLED_CIPHERS)
|
|
|
def test_enabled_tls_ciphers(host, cipher):
|
|
|
"""
|
|
|
Tests available TLS ciphers on the server.
|
|
|
"""
|
|
|
|
|
|
hostname = host.run('hostname').stdout.strip()
|
|
|
fqdn = hostname[:hostname.rfind('-')]
|
|
|
report_root = ElementTree.fromstring(report_content)
|
|
|
|
|
|
client = host.run("echo 'Q' | openssl s_client -cipher %s -connect %s:443", cipher, fqdn)
|
|
|
assert client.rc == 0
|
|
|
assert cipher in client.stdout
|
|
|
tls_versions = []
|
|
|
tls_ciphers = set()
|
|
|
|
|
|
for child in report_root.findall("./host/ports/port/script/table"):
|
|
|
tls_versions.append(child.attrib['key'])
|
|
|
|
|
|
@pytest.mark.parametrize("cipher", DISABLED_CIPHERS)
|
|
|
def test_disabled_tls_ciphers(host, cipher):
|
|
|
"""
|
|
|
Tests available TLS ciphers on the server.
|
|
|
"""
|
|
|
for child in report_root.findall(".//table[@key='ciphers']/table/elem[@key='name']"):
|
|
|
tls_ciphers.add(child.text)
|
|
|
|
|
|
hostname = host.run('hostname').stdout.strip()
|
|
|
fqdn = hostname[:hostname.rfind('-')]
|
|
|
tls_versions.sort()
|
|
|
tls_ciphers = sorted(list(tls_ciphers))
|
|
|
|
|
|
client = host.run("echo 'Q' | openssl s_client -cipher %s -connect %s:443", cipher, fqdn)
|
|
|
assert client.rc != 0
|
|
|
assert cipher not in client.stdout
|
|
|
assert tls_versions == expected_tls_versions
|
|
|
assert tls_ciphers == expected_tls_ciphers
|
|
|
|
|
|
|
|
|
def test_https_enforcement(host):
|