blob: 004717d61081cd967f28517d1c072b92158a11c3 [file] [log] [blame]
Andrew Geisslerd5838332022-05-27 11:33:10 -05001# Copyright (C) 2022 Armin Kuster <akuster808@gmail.com>
2# Copyright (C) 2022 Anton Antonov <Anton.Antonov@arm.com>
3#
4import re
5from tempfile import mkstemp
6
7from oeqa.runtime.case import OERuntimeTestCase
8from oeqa.core.decorator.depends import OETestDepends
9from oeqa.runtime.decorator.package import OEHasPackage
10from oeqa.core.decorator.data import skipIfNotFeature
11
12class ParsecTest(OERuntimeTestCase):
13 @classmethod
14 def setUpClass(cls):
15 cls.toml_file = '/etc/parsec/config.toml'
Patrick Williams92b42cb2022-09-03 06:53:57 -050016 cls.tc.target.run('cp -p %s %s-original' % (cls.toml_file, cls.toml_file))
Andrew Geissler615f2f12022-07-15 14:00:58 -050017
Andrew Geisslerd5838332022-05-27 11:33:10 -050018 def setUp(self):
19 super(ParsecTest, self).setUp()
20 if 'systemd' in self.tc.td['DISTRO_FEATURES']:
21 self.parsec_status='systemctl status -l parsec'
22 self.parsec_reload='systemctl restart parsec'
23 else:
24 self.parsec_status='pgrep -l parsec'
25 self.parsec_reload='/etc/init.d/parsec reload'
26
Patrick Williams8e7b46e2023-05-01 14:19:06 -050027 def tearDown(self):
28 self.target.run('sync')
29 super(ParsecTest, self).tearDown()
30
Andrew Geisslerd5838332022-05-27 11:33:10 -050031 def copy_subconfig(self, cfg, provider):
32 """ Copy a provider configuration to target and append it to Parsec config """
33
34 tmp_fd, tmp_path = mkstemp()
35 with os.fdopen(tmp_fd, 'w') as f:
36 f.write('\n'.join(cfg))
37
38 (status, output) = self.target.copyTo(tmp_path, "%s-%s" % (self.toml_file, provider))
39 self.assertEqual(status, 0, msg='File could not be copied.\n%s' % output)
40 status, output = self.target.run('cat %s-%s >>%s' % (self.toml_file, provider, self.toml_file))
41 os.remove(tmp_path)
42
Patrick Williams92b42cb2022-09-03 06:53:57 -050043 def restore_parsec_config(self):
44 """ Restore original Parsec config """
45 self.target.run('cp -p %s-original %s' % (self.toml_file, self.toml_file))
46 self.target.run(self.parsec_reload)
47
Andrew Geisslerd5838332022-05-27 11:33:10 -050048 def check_parsec_providers(self, provider=None, prov_id=None):
49 """ Get Parsec providers list and check for one if defined """
50
51 status, output = self.target.run(self.parsec_status)
52 self.assertEqual(status, 0, msg='Parsec service is not running.\n%s' % output)
53
54 status, output = self.target.run('parsec-tool list-providers')
55 self.assertEqual(status, 0, msg='Cannot get a list of Parsec providers.\n%s' % output)
56 if provider and prov_id:
57 self.assertIn("ID: 0x0%d (%s provider)" % (prov_id, provider),
58 output, msg='%s provider is not configured.' % provider)
59
Patrick Williams8e7b46e2023-05-01 14:19:06 -050060 def run_cli_tests(self, prov_id=None, extra_params=""):
Andrew Geisslerd5838332022-05-27 11:33:10 -050061 """ Run Parsec CLI end-to-end tests against one or all providers """
62
Patrick Williams8e7b46e2023-05-01 14:19:06 -050063 status, output = self.target.run('parsec-cli-tests.sh %s %s' % ("-%d" % prov_id if prov_id else "", extra_params))
Andrew Geisslerd5838332022-05-27 11:33:10 -050064 self.assertEqual(status, 0, msg='Parsec CLI tests failed.\n %s' % output)
65
Patrick Williams92b42cb2022-09-03 06:53:57 -050066 def check_packageconfig(self, prov):
67 """ Check that the require provider is included in Parsec """
Patrick Williams8e7b46e2023-05-01 14:19:06 -050068
69 if 'PACKAGECONFIG:pn-parsec-service' in self.tc.td.keys():
70 providers = self.tc.td['PACKAGECONFIG:pn-parsec-service']
71 else:
72 # PACKAGECONFIG is not defined in local.conf
73 # Let's use the default value
74 providers = "PKCS11 MBED-CRYPTO"
75 if 'tpm2' in self.tc.td['DISTRO_FEATURES']:
76 providers += " TPM"
77 if prov not in providers:
Patrick Williams92b42cb2022-09-03 06:53:57 -050078 self.skipTest('%s provider is not included in Parsec. Parsec PACKAGECONFIG: "%s"' % \
Patrick Williams8e7b46e2023-05-01 14:19:06 -050079 (prov, providers))
Patrick Williams92b42cb2022-09-03 06:53:57 -050080
81 def check_packages(self, prov, packages):
82 """ Check for the required packages for Parsec providers software backends """
83 if isinstance(packages, str):
84 need_pkgs = set([packages,])
85 else:
86 need_pkgs = set(packages)
87
88 if not self.tc.image_packages.issuperset(need_pkgs):
89 self.skipTest('%s provider is not configured and packages "%s" are not included into the image' % \
90 (prov, need_pkgs))
91
Andrew Geisslerd5838332022-05-27 11:33:10 -050092 @OEHasPackage(['parsec-service'])
93 @OETestDepends(['ssh.SSHTest.test_ssh'])
94 def test_all_providers(self):
95 """ Test Parsec service with all pre-defined providers """
96
97 self.check_parsec_providers()
98 self.run_cli_tests()
99
100 def configure_tpm_provider(self):
101 """ Create Parsec TPM provider configuration """
102
103 cfg = [
104 '',
105 '[[provider]]',
106 'name = "tpm-provider"',
107 'provider_type = "Tpm"',
108 'key_info_manager = "sqlite-manager"',
109 'tcti = "swtpm:port=2321"',
110 'owner_hierarchy_auth = ""',
111 ]
112 self.copy_subconfig(cfg, "TPM")
113
114 cmds = [
115 'mkdir /tmp/myvtpm',
116 'swtpm socket -d --tpmstate dir=/tmp/myvtpm --tpm2 --ctrl type=tcp,port=2322 --server type=tcp,port=2321 --flags not-need-init',
117 'tpm2_startup -c -T "swtpm:port=2321"',
Patrick Williams92b42cb2022-09-03 06:53:57 -0500118 'chown -R parsec /tmp/myvtpm',
Andrew Geisslerd5838332022-05-27 11:33:10 -0500119 self.parsec_reload,
Patrick Williams92b42cb2022-09-03 06:53:57 -0500120 'sleep 5',
Andrew Geisslerd5838332022-05-27 11:33:10 -0500121 ]
122
123 for cmd in cmds:
124 status, output = self.target.run(cmd)
125 self.assertEqual(status, 0, msg='\n'.join([cmd, output]))
126
127 @OEHasPackage(['parsec-service'])
Andrew Geisslerd5838332022-05-27 11:33:10 -0500128 @skipIfNotFeature('tpm2','Test parsec_tpm_provider requires tpm2 to be in DISTRO_FEATURES')
Patrick Williams92b42cb2022-09-03 06:53:57 -0500129 @OETestDepends(['ssh.SSHTest.test_ssh'])
Andrew Geisslerd5838332022-05-27 11:33:10 -0500130 def test_tpm_provider(self):
131 """ Configure and test Parsec TPM provider with swtpm as a backend """
132
Patrick Williams92b42cb2022-09-03 06:53:57 -0500133 self.check_packageconfig("TPM")
134
135 reconfigure = False
Andrew Geisslerd5838332022-05-27 11:33:10 -0500136 prov_id = 3
Patrick Williams92b42cb2022-09-03 06:53:57 -0500137 try:
138 # Chech if the provider is already configured
139 self.check_parsec_providers("TPM", prov_id)
140 except:
141 # Try to test the provider with a software backend
142 self.check_packages("TPM", ['swtpm', 'tpm2-tools'])
143 reconfigure = True
144 self.configure_tpm_provider()
145 self.check_parsec_providers("TPM", prov_id)
146
Andrew Geisslerd5838332022-05-27 11:33:10 -0500147 self.run_cli_tests(prov_id)
Patrick Williams92b42cb2022-09-03 06:53:57 -0500148 self.restore_parsec_config()
149
150 if reconfigure:
151 self.target.run('swtpm_ioctl -s --tcp :2322')
Andrew Geisslerd5838332022-05-27 11:33:10 -0500152
153 def configure_pkcs11_provider(self):
154 """ Create Parsec PKCS11 provider configuration """
155
156 status, output = self.target.run('softhsm2-util --init-token --free --label "Parsec Service" --pin 123456 --so-pin 123456')
157 self.assertEqual(status, 0, msg='Failed to init PKCS11 token.\n%s' % output)
158
159 slot = re.search('The token has been initialized and is reassigned to slot (\d*)', output)
160 if slot is None:
161 self.fail('Failed to get PKCS11 slot serial number.\n%s' % output)
162 self.assertNotEqual(slot.group(1), None, msg='Failed to get PKCS11 slot serial number.\n%s' % output)
163
164 cfg = [
165 '',
166 '[[provider]]',
167 'name = "pkcs11-provider"',
168 'provider_type = "Pkcs11"',
169 'key_info_manager = "sqlite-manager"',
170 'library_path = "/usr/lib/softhsm/libsofthsm2.so"',
171 'slot_number = %s' % slot.group(1),
172 'user_pin = "123456"',
173 'allow_export = true',
174 ]
175 self.copy_subconfig(cfg, "PKCS11")
176
177 status, output = self.target.run('for d in /var/lib/softhsm/tokens/*; do chown -R parsec $d; done')
178 status, output = self.target.run(self.parsec_reload)
179 self.assertEqual(status, 0, msg='Failed to reload Parsec.\n%s' % output)
180
181 @OEHasPackage(['parsec-service'])
Patrick Williams92b42cb2022-09-03 06:53:57 -0500182 @OETestDepends(['ssh.SSHTest.test_ssh'])
Andrew Geisslerd5838332022-05-27 11:33:10 -0500183 def test_pkcs11_provider(self):
184 """ Configure and test Parsec PKCS11 provider with softhsm as a backend """
185
Patrick Williams92b42cb2022-09-03 06:53:57 -0500186 self.check_packageconfig("PKCS11")
Andrew Geisslerd5838332022-05-27 11:33:10 -0500187 prov_id = 2
Patrick Williams92b42cb2022-09-03 06:53:57 -0500188 try:
189 # Chech if the provider is already configured
190 self.check_parsec_providers("PKCS #11", prov_id)
191 except:
192 # Try to test the provider with a software backend
193 self.check_packages("PKCS11", 'softhsm')
194 self.configure_pkcs11_provider()
195 self.check_parsec_providers("PKCS #11", prov_id)
196
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500197 # Software PKCS11 we use for OE QA testing
198 # doesn't support RSA-OAEP(SHA256) encryption/decryption operations
199 self.run_cli_tests(prov_id, "--no-oaep")
Patrick Williams92b42cb2022-09-03 06:53:57 -0500200 self.restore_parsec_config()
201
202 def configure_TS_provider(self):
203 """ Create Trusted Services provider configuration """
204
205 cfg = [
206 '',
207 '[[provider]]',
208 'name = "trusted-service-provider"',
209 'provider_type = "TrustedService"',
210 'key_info_manager = "sqlite-manager"',
211 ]
212 self.copy_subconfig(cfg, "TS")
213
214 status, output = self.target.run(self.parsec_reload)
215 self.assertEqual(status, 0, msg='Failed to reload Parsec.\n%s' % output)
216
217 @OEHasPackage(['parsec-service'])
218 @OETestDepends(['ssh.SSHTest.test_ssh'])
219 def test_TS_provider(self):
220 """ Configure and test Parsec PKCS11 provider with softhsm as a backend """
221
222 self.check_packageconfig("TS")
223 prov_id = 4
224 try:
225 # Chech if the provider is already configured
226 self.check_parsec_providers("Trusted Service", prov_id)
227 except:
228 self.configure_TS_provider()
229 self.check_parsec_providers("Trusted Service", prov_id)
230
231 self.run_cli_tests(prov_id)
232 self.restore_parsec_config()