Skip to content

Commit f570ba3

Browse files
MOS CIGerrit Code Review
authored andcommitted
Merge "[functional] Add FIPS tests for Libvirt"
2 parents 78694a1 + 8479ab7 commit f570ba3

3 files changed

Lines changed: 227 additions & 1 deletion

File tree

‎rockoon/tests/functional/base.py‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import logging
22
import exec_helpers
3+
import os
34
import paramiko
45
import socket
56
import ssl
7+
import tempfile
68

79
from kombu import Connection
810
from unittest import TestCase
@@ -907,3 +909,22 @@ def check_ciphersuite(
907909
sock.close()
908910

909911
self.assertTrue(test_passed)
912+
913+
def exec_script_in_pod(self, pod, container, script_name):
914+
cmd_res = ""
915+
temp_name = next(tempfile._get_candidate_names())
916+
remote_script_name = f"/tmp/{temp_name}.py"
917+
base_folder = os.path.dirname(os.path.realpath(__file__))
918+
with open(f"{base_folder}/../scripts/{script_name}") as f:
919+
script = f.read()
920+
try:
921+
cmd_res = pod.exec(
922+
["bash", "-c", f"echo '{script}' > {remote_script_name}"],
923+
container,
924+
)
925+
if cmd_res["error_json"]["status"] == "Success":
926+
pod.exec(["chmod", "+x", remote_script_name], container)
927+
cmd_res = pod.exec([remote_script_name], container)
928+
finally:
929+
pod.exec(["rm", "-f", remote_script_name], container)
930+
return cmd_res

‎rockoon/tests/functional/deployment/parallel/test_compute.py‎

Lines changed: 178 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
import unittest
22
import pytest
3+
import json
4+
import os
5+
import tempfile
36

7+
from parameterized import parameterized
48
from rockoon.tests.functional import base
5-
from rockoon import constants
9+
from rockoon import constants, kube, settings
610

711

812
@pytest.mark.xdist_group("exporter-compute-network")
@@ -47,3 +51,176 @@ def test_novnc_tls(self):
4751
f"The tls pattern string '{tls_pattern}'"
4852
f" not found in qemu-system process line {qemu_psline}",
4953
)
54+
55+
56+
class LibvirtFipsFunctionalTestCase(base.BaseFunctionalTestCase):
57+
"""Check Libvirt and QEMU Fips compliance"""
58+
59+
@classmethod
60+
def setUpClass(cls):
61+
super(LibvirtFipsFunctionalTestCase, cls).setUpClass()
62+
if (
63+
not cls.osdpl.obj["spec"]["features"]
64+
.get("nova", {})
65+
.get("libvirt", {})
66+
.get("tls", {})
67+
.get("enabled", False)
68+
):
69+
raise unittest.SkipTest("Libvirt TLS is not enabled.")
70+
libvirt_secret = kube.find(
71+
kube.Secret,
72+
"libvirt-server-certs",
73+
settings.OSCTL_OS_DEPLOYMENT_NAMESPACE,
74+
silent=True,
75+
)
76+
cls.assertIsNotNone(
77+
libvirt_secret,
78+
f"Can't get libvirt-ca-bundle secret in {settings.OSCTL_OS_DEPLOYMENT_NAMESPACE} namespace.",
79+
)
80+
secret_data = libvirt_secret.data_decoded
81+
with tempfile.NamedTemporaryFile(dir="/tmp", delete=False) as f:
82+
f.write(secret_data["ca.crt"].encode("utf-8"))
83+
cls.ca_bundle = f.name
84+
85+
def setUp(self):
86+
super(LibvirtFipsFunctionalTestCase, self).setUp()
87+
kube_api = kube.kube_client()
88+
pods = kube.Pod.objects(kube_api).filter(
89+
namespace=settings.OSCTL_OS_DEPLOYMENT_NAMESPACE,
90+
selector={
91+
"application": "libvirt",
92+
"component": "libvirt",
93+
},
94+
)
95+
pods = [pod for pod in pods]
96+
self.assertTrue(
97+
pods,
98+
"Failed to get Libvirt pods.",
99+
)
100+
self.libvirt_pod = pods[0]
101+
102+
@classmethod
103+
def tearDownClass(cls):
104+
super(LibvirtFipsFunctionalTestCase, cls).tearDownClass()
105+
if cls.ca_bundle:
106+
os.remove(cls.ca_bundle)
107+
108+
@parameterized.expand(
109+
[
110+
# Any connections with TLS 1 and TLS 1.1 should fail
111+
("TLSv1.0", "auto", "negative"),
112+
("TLSv1.1", "auto", "negative"),
113+
# The list of cipher suites for TLS 1.2 was obtained from the output
114+
# of the following command:
115+
# openssl ciphers -v 'ALL' | grep "TLSv1.2" | awk '{print $1}'
116+
("TLSv1.2", "ECDHE-RSA-AES256-GCM-SHA384", "positive"),
117+
("TLSv1.2", "ECDHE-RSA-AES128-GCM-SHA256", "positive"),
118+
("TLSv1.2", "ECDHE-ECDSA-AES256-GCM-SHA384", "negative"),
119+
("TLSv1.2", "DHE-DSS-AES256-GCM-SHA384", "negative"),
120+
("TLSv1.2", "DHE-RSA-AES256-GCM-SHA384", "negative"),
121+
("TLSv1.2", "ECDHE-ECDSA-CHACHA20-POLY1305", "negative"),
122+
("TLSv1.2", "ECDHE-RSA-CHACHA20-POLY1305", "negative"),
123+
("TLSv1.2", "DHE-RSA-CHACHA20-POLY1305", "negative"),
124+
("TLSv1.2", "ECDHE-ECDSA-AES256-CCM8", "negative"),
125+
("TLSv1.2", "ECDHE-ECDSA-AES256-CCM", "negative"),
126+
("TLSv1.2", "DHE-RSA-AES256-CCM8", "negative"),
127+
("TLSv1.2", "DHE-RSA-AES256-CCM", "negative"),
128+
("TLSv1.2", "ECDHE-ECDSA-ARIA256-GCM-SHA384", "negative"),
129+
("TLSv1.2", "ECDHE-ARIA256-GCM-SHA384", "negative"),
130+
("TLSv1.2", "DHE-DSS-ARIA256-GCM-SHA384", "negative"),
131+
("TLSv1.2", "DHE-RSA-ARIA256-GCM-SHA384", "negative"),
132+
("TLSv1.2", "ADH-AES256-GCM-SHA384", "negative"),
133+
("TLSv1.2", "ECDHE-ECDSA-AES128-GCM-SHA256", "negative"),
134+
("TLSv1.2", "DHE-DSS-AES128-GCM-SHA256", "negative"),
135+
("TLSv1.2", "DHE-RSA-AES128-GCM-SHA256", "negative"),
136+
("TLSv1.2", "ECDHE-ECDSA-AES128-CCM8", "negative"),
137+
("TLSv1.2", "ECDHE-ECDSA-AES128-CCM", "negative"),
138+
("TLSv1.2", "DHE-RSA-AES128-CCM8", "negative"),
139+
("TLSv1.2", "DHE-RSA-AES128-CCM", "negative"),
140+
("TLSv1.2", "ECDHE-ECDSA-ARIA128-GCM-SHA256", "negative"),
141+
("TLSv1.2", "ECDHE-ARIA128-GCM-SHA256", "negative"),
142+
("TLSv1.2", "DHE-DSS-ARIA128-GCM-SHA256", "negative"),
143+
("TLSv1.2", "DHE-RSA-ARIA128-GCM-SHA256", "negative"),
144+
("TLSv1.2", "ADH-AES128-GCM-SHA256", "negative"),
145+
("TLSv1.2", "ECDHE-ECDSA-AES256-SHA384", "negative"),
146+
("TLSv1.2", "ECDHE-RSA-AES256-SHA384", "negative"),
147+
("TLSv1.2", "DHE-RSA-AES256-SHA256", "negative"),
148+
("TLSv1.2", "DHE-DSS-AES256-SHA256", "negative"),
149+
("TLSv1.2", "ECDHE-ECDSA-CAMELLIA256-SHA384", "negative"),
150+
("TLSv1.2", "ECDHE-RSA-CAMELLIA256-SHA384", "negative"),
151+
("TLSv1.2", "DHE-RSA-CAMELLIA256-SHA256", "negative"),
152+
("TLSv1.2", "DHE-DSS-CAMELLIA256-SHA256", "negative"),
153+
("TLSv1.2", "ADH-AES256-SHA256", "negative"),
154+
("TLSv1.2", "ADH-CAMELLIA256-SHA256", "negative"),
155+
("TLSv1.2", "ECDHE-ECDSA-AES128-SHA256", "negative"),
156+
("TLSv1.2", "ECDHE-RSA-AES128-SHA256", "negative"),
157+
("TLSv1.2", "DHE-RSA-AES128-SHA256", "negative"),
158+
("TLSv1.2", "DHE-DSS-AES128-SHA256", "negative"),
159+
("TLSv1.2", "ECDHE-ECDSA-CAMELLIA128-SHA256", "negative"),
160+
("TLSv1.2", "ECDHE-RSA-CAMELLIA128-SHA256", "negative"),
161+
("TLSv1.2", "DHE-RSA-CAMELLIA128-SHA256", "negative"),
162+
("TLSv1.2", "DHE-DSS-CAMELLIA128-SHA256", "negative"),
163+
("TLSv1.2", "ADH-AES128-SHA256", "negative"),
164+
("TLSv1.2", "ADH-CAMELLIA128-SHA256", "negative"),
165+
("TLSv1.2", "RSA-PSK-AES256-GCM-SHA384", "negative"),
166+
("TLSv1.2", "DHE-PSK-AES256-GCM-SHA384", "negative"),
167+
("TLSv1.2", "RSA-PSK-CHACHA20-POLY1305", "negative"),
168+
("TLSv1.2", "DHE-PSK-CHACHA20-POLY1305", "negative"),
169+
("TLSv1.2", "ECDHE-PSK-CHACHA20-POLY1305", "negative"),
170+
("TLSv1.2", "DHE-PSK-AES256-CCM8", "negative"),
171+
("TLSv1.2", "DHE-PSK-AES256-CCM", "negative"),
172+
("TLSv1.2", "RSA-PSK-ARIA256-GCM-SHA384", "negative"),
173+
("TLSv1.2", "DHE-PSK-ARIA256-GCM-SHA384", "negative"),
174+
("TLSv1.2", "AES256-GCM-SHA384", "positive"),
175+
("TLSv1.2", "AES256-CCM8", "negative"),
176+
("TLSv1.2", "AES256-CCM", "positive"),
177+
("TLSv1.2", "ARIA256-GCM-SHA384", "negative"),
178+
("TLSv1.2", "PSK-AES256-GCM-SHA384", "negative"),
179+
("TLSv1.2", "PSK-CHACHA20-POLY1305", "negative"),
180+
("TLSv1.2", "PSK-AES256-CCM8", "negative"),
181+
("TLSv1.2", "PSK-AES256-CCM", "negative"),
182+
("TLSv1.2", "PSK-ARIA256-GCM-SHA384", "negative"),
183+
("TLSv1.2", "RSA-PSK-AES128-GCM-SHA256", "negative"),
184+
("TLSv1.2", "DHE-PSK-AES128-GCM-SHA256", "negative"),
185+
("TLSv1.2", "DHE-PSK-AES128-CCM8", "negative"),
186+
("TLSv1.2", "DHE-PSK-AES128-CCM", "negative"),
187+
("TLSv1.2", "RSA-PSK-ARIA128-GCM-SHA256", "negative"),
188+
("TLSv1.2", "DHE-PSK-ARIA128-GCM-SHA256", "negative"),
189+
("TLSv1.2", "AES128-GCM-SHA256", "positive"),
190+
("TLSv1.2", "AES128-CCM8", "negative"),
191+
("TLSv1.2", "AES128-CCM", "positive"),
192+
("TLSv1.2", "ARIA128-GCM-SHA256", "negative"),
193+
("TLSv1.2", "PSK-AES128-GCM-SHA256", "negative"),
194+
("TLSv1.2", "PSK-AES128-CCM8", "negative"),
195+
("TLSv1.2", "PSK-AES128-CCM", "negative"),
196+
("TLSv1.2", "PSK-ARIA128-GCM-SHA256", "negative"),
197+
("TLSv1.2", "AES256-SHA256", "negative"),
198+
("TLSv1.2", "CAMELLIA256-SHA256", "negative"),
199+
("TLSv1.2", "AES128-SHA256", "negative"),
200+
("TLSv1.2", "CAMELLIA128-SHA256", "negative"),
201+
# The TLS 1.3 has its own mechanic for ciphersite management but
202+
# it didn't implement in Python 3.12 so we can't set cipher for testing
203+
# There is a patch https://github.com/python/cpython/commit/bacb7771fb0390a1ae7f83b7bec97e5ce1d60d26
204+
# that will allow TLS 1.3 ciphersuites management in the future Python
205+
# releases
206+
("TLSv1.3", "auto", "positive"),
207+
],
208+
name_func=base.default_custom_name_func,
209+
)
210+
def test_ssl_connection(self, tls_version, cipher, expected_state):
211+
self.check_ciphersuite(
212+
self.libvirt_pod.obj["status"]["hostIP"],
213+
16514,
214+
tls_version,
215+
cipher,
216+
expected_state,
217+
self.ca_bundle,
218+
)
219+
220+
def test_libraries_mode(self):
221+
response = self.exec_script_in_pod(
222+
self.libvirt_pod, "libvirt", "check_libs_fips_mode.py"
223+
)
224+
self.assertTrue(response["error_json"]["status"] == "Success")
225+
result = json.loads(response["stdout"])
226+
self.assertTrue(result["gnutls"] and result["libcrypto"])
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#!/usr/bin/env python3
2+
import ctypes
3+
from ctypes.util import find_library
4+
import json
5+
6+
lib = ctypes.CDLL(find_library("gnutls"))
7+
result = {"gnutls": False, "libcrypto": False}
8+
try:
9+
# https://www.gnutls.org/manual/html_node/Core-TLS-API.html#gnutls_005fglobal_005finit
10+
# https://www.gnutls.org/manual/html_node/Core-TLS-API.html#gnutls_005ffips140_005fmode_005fenabled
11+
lib.gnutls_global_init.restype = ctypes.c_int
12+
lib.gnutls_fips140_mode_enabled.restype = ctypes.c_uint
13+
14+
if lib.gnutls_global_init() == 0:
15+
result["gnutls"] = lib.gnutls_fips140_mode_enabled() != 0
16+
lib.gnutls_global_deinit()
17+
except AttributeError:
18+
pass
19+
20+
lib = ctypes.CDLL(find_library("crypto"))
21+
try:
22+
# https://manpages.debian.org/testing/libssl-doc/EVP_default_properties_is_fips_enabled.3ssl.en.html
23+
lib.EVP_default_properties_is_fips_enabled.restype = ctypes.c_int
24+
result["libcrypto"] = lib.EVP_default_properties_is_fips_enabled(0) == 1
25+
except AttributeError:
26+
pass
27+
28+
print(json.dumps(result))

0 commit comments

Comments
 (0)