blob: c8bf0799bfcaa8cf396430703ef16b399d3dc1ca [file] [log] [blame]
Gilles Peskine15c2cbf2020-06-25 18:36:28 +02001#!/usr/bin/env python3
2
3"""Analyze the test outcomes from a full CI run.
4
5This script can also run on outcomes from a partial run, but the results are
6less likely to be useful.
7"""
8
9import argparse
10import sys
11import traceback
Przemek Stekiel85c54ea2022-11-17 11:50:23 +010012import re
Valerio Settia2663322023-03-24 08:20:18 +010013import subprocess
14import os
Gilles Peskine15c2cbf2020-06-25 18:36:28 +020015
Gilles Peskine8d3c70a2020-06-25 18:37:43 +020016import check_test_cases
17
Gilles Peskine15c2cbf2020-06-25 18:36:28 +020018class Results:
19 """Process analysis results."""
20
21 def __init__(self):
22 self.error_count = 0
23 self.warning_count = 0
24
25 @staticmethod
26 def log(fmt, *args, **kwargs):
27 sys.stderr.write((fmt + '\n').format(*args, **kwargs))
28
29 def error(self, fmt, *args, **kwargs):
30 self.log('Error: ' + fmt, *args, **kwargs)
31 self.error_count += 1
32
33 def warning(self, fmt, *args, **kwargs):
34 self.log('Warning: ' + fmt, *args, **kwargs)
35 self.warning_count += 1
36
37class TestCaseOutcomes:
38 """The outcomes of one test case across many configurations."""
39 # pylint: disable=too-few-public-methods
40
41 def __init__(self):
Gilles Peskine3d863f22020-06-26 13:02:30 +020042 # Collect a list of witnesses of the test case succeeding or failing.
43 # Currently we don't do anything with witnesses except count them.
44 # The format of a witness is determined by the read_outcome_file
45 # function; it's the platform and configuration joined by ';'.
Gilles Peskine15c2cbf2020-06-25 18:36:28 +020046 self.successes = []
47 self.failures = []
48
49 def hits(self):
50 """Return the number of times a test case has been run.
51
52 This includes passes and failures, but not skips.
53 """
54 return len(self.successes) + len(self.failures)
55
Valerio Settia2663322023-03-24 08:20:18 +010056def execute_reference_driver_tests(ref_component, driver_component, outcome_file):
Valerio Setti22992a02023-03-29 11:15:28 +020057 """Run the tests specified in ref_component and driver_component. Results
58 are stored in the output_file and they will be used for the following
Valerio Settia2663322023-03-24 08:20:18 +010059 coverage analysis"""
60 # If the outcome file already exists, we assume that the user wants to
61 # perform the comparison analysis again without repeating the tests.
62 if os.path.exists(outcome_file):
63 Results.log("Outcome file (" + outcome_file + ") already exists. " + \
64 "Tests will be skipped.")
65 return
66
67 shell_command = "tests/scripts/all.sh --outcome-file " + outcome_file + \
68 " " + ref_component + " " + driver_component
Valerio Settif109c662023-03-29 11:15:44 +020069 Results.log("Running: " + shell_command)
Valerio Settia2663322023-03-24 08:20:18 +010070 ret_val = subprocess.run(shell_command.split(), check=False).returncode
71
72 if ret_val != 0:
73 Results.log("Error: failed to run reference/driver components")
74 sys.exit(ret_val)
75
Tomás Gonzálezb401e112023-08-11 15:22:04 +010076def analyze_coverage(results, outcomes, allow_list, full_coverage):
Gilles Peskine8d3c70a2020-06-25 18:37:43 +020077 """Check that all available test cases are executed at least once."""
Gilles Peskine686c2922022-01-07 15:58:38 +010078 available = check_test_cases.collect_available_test_cases()
Gilles Peskine8d3c70a2020-06-25 18:37:43 +020079 for key in available:
80 hits = outcomes[key].hits() if key in outcomes else 0
Tomás González07bdcc22023-08-11 14:59:03 +010081 if hits == 0 and key not in allow_list:
Tomás Gonzálezb401e112023-08-11 15:22:04 +010082 if full_coverage:
83 results.error('Test case not executed: {}', key)
84 else:
85 results.warning('Test case not executed: {}', key)
Tomás González07bdcc22023-08-11 14:59:03 +010086 elif hits != 0 and key in allow_list:
87 # Test Case should be removed from the allow list.
Tomás González7ebb18f2023-08-22 09:40:23 +010088 if full_coverage:
Tomás Gonzáleza0631442023-08-22 12:17:57 +010089 results.error('Allow listed test case was executed: {}', key)
Tomás González7ebb18f2023-08-22 09:40:23 +010090 else:
91 results.warning('Allow listed test case was executed: {}', key)
Gilles Peskine8d3c70a2020-06-25 18:37:43 +020092
Valerio Setti3002c992023-01-18 17:28:36 +010093def analyze_driver_vs_reference(outcomes, component_ref, component_driver,
94 ignored_suites, ignored_test=None):
Przemek Stekiel4e955902022-10-21 13:42:08 +020095 """Check that all tests executed in the reference component are also
96 executed in the corresponding driver component.
Valerio Setti3002c992023-01-18 17:28:36 +010097 Skip:
98 - full test suites provided in ignored_suites list
99 - only some specific test inside a test suite, for which the corresponding
100 output string is provided
Przemek Stekiel4e955902022-10-21 13:42:08 +0200101 """
Przemek Stekiel4e955902022-10-21 13:42:08 +0200102 available = check_test_cases.collect_available_test_cases()
103 result = True
104
105 for key in available:
Przemek Stekiel4e955902022-10-21 13:42:08 +0200106 # Continue if test was not executed by any component
107 hits = outcomes[key].hits() if key in outcomes else 0
Przemek Stekielc86dedf2022-10-24 09:16:04 +0200108 if hits == 0:
Przemek Stekiel4e955902022-10-21 13:42:08 +0200109 continue
Valerio Setti00c1ccb2023-02-02 11:33:31 +0100110 # Skip ignored test suites
111 full_test_suite = key.split(';')[0] # retrieve full test suite name
112 test_string = key.split(';')[1] # retrieve the text string of this test
113 test_suite = full_test_suite.split('.')[0] # retrieve main part of test suite name
Manuel Pégourié-Gonnard7d381f52023-03-17 15:13:08 +0100114 if test_suite in ignored_suites or full_test_suite in ignored_suites:
Valerio Setti00c1ccb2023-02-02 11:33:31 +0100115 continue
Valerio Setti3002c992023-01-18 17:28:36 +0100116 if ((full_test_suite in ignored_test) and
117 (test_string in ignored_test[full_test_suite])):
118 continue
Przemek Stekiel4e955902022-10-21 13:42:08 +0200119 # Search for tests that run in reference component and not in driver component
120 driver_test_passed = False
121 reference_test_passed = False
122 for entry in outcomes[key].successes:
Przemek Stekiel51f30ff2022-11-09 12:07:29 +0100123 if component_driver in entry:
Przemek Stekiel4e955902022-10-21 13:42:08 +0200124 driver_test_passed = True
Przemek Stekiel51f30ff2022-11-09 12:07:29 +0100125 if component_ref in entry:
Przemek Stekiel4e955902022-10-21 13:42:08 +0200126 reference_test_passed = True
Manuel Pégourié-Gonnardc6967d22022-12-30 13:40:34 +0100127 if(reference_test_passed and not driver_test_passed):
Valerio Setti3951d1b2023-03-13 18:37:34 +0100128 Results.log(key)
Przemek Stekiel4e955902022-10-21 13:42:08 +0200129 result = False
130 return result
131
Tomás Gonzálezb401e112023-08-11 15:22:04 +0100132def analyze_outcomes(outcomes, args):
Gilles Peskine15c2cbf2020-06-25 18:36:28 +0200133 """Run all analyses on the given outcome collection."""
134 results = Results()
Tomás Gonzálezb401e112023-08-11 15:22:04 +0100135 analyze_coverage(results, outcomes, args['allow_list'],
136 args['full_coverage'])
Gilles Peskine15c2cbf2020-06-25 18:36:28 +0200137 return results
138
139def read_outcome_file(outcome_file):
140 """Parse an outcome file and return an outcome collection.
141
142An outcome collection is a dictionary mapping keys to TestCaseOutcomes objects.
143The keys are the test suite name and the test case description, separated
144by a semicolon.
145"""
146 outcomes = {}
147 with open(outcome_file, 'r', encoding='utf-8') as input_file:
148 for line in input_file:
149 (platform, config, suite, case, result, _cause) = line.split(';')
150 key = ';'.join([suite, case])
151 setup = ';'.join([platform, config])
152 if key not in outcomes:
153 outcomes[key] = TestCaseOutcomes()
154 if result == 'PASS':
155 outcomes[key].successes.append(setup)
156 elif result == 'FAIL':
157 outcomes[key].failures.append(setup)
158 return outcomes
159
Przemek Stekiel4d13c832022-10-26 16:11:26 +0200160def do_analyze_coverage(outcome_file, args):
Przemek Stekiel6856f4c2022-11-09 10:50:29 +0100161 """Perform coverage analysis."""
Gilles Peskine15c2cbf2020-06-25 18:36:28 +0200162 outcomes = read_outcome_file(outcome_file)
Valerio Setti3951d1b2023-03-13 18:37:34 +0100163 Results.log("\n*** Analyze coverage ***\n")
Tomás Gonzálezb401e112023-08-11 15:22:04 +0100164 results = analyze_outcomes(outcomes, args)
Przemek Stekielc86dedf2022-10-24 09:16:04 +0200165 return results.error_count == 0
Przemek Stekiel4e955902022-10-21 13:42:08 +0200166
Przemek Stekiel4d13c832022-10-26 16:11:26 +0200167def do_analyze_driver_vs_reference(outcome_file, args):
Przemek Stekiel4e955902022-10-21 13:42:08 +0200168 """Perform driver vs reference analyze."""
Valerio Settia2663322023-03-24 08:20:18 +0100169 execute_reference_driver_tests(args['component_ref'], \
170 args['component_driver'], outcome_file)
171
Valerio Setti3002c992023-01-18 17:28:36 +0100172 ignored_suites = ['test_suite_' + x for x in args['ignored_suites']]
Przemek Stekiel51f30ff2022-11-09 12:07:29 +0100173
Przemek Stekiel4e955902022-10-21 13:42:08 +0200174 outcomes = read_outcome_file(outcome_file)
Valerio Setti3951d1b2023-03-13 18:37:34 +0100175 Results.log("\n*** Analyze driver {} vs reference {} ***\n".format(
Manuel Pégourié-Gonnardc6967d22022-12-30 13:40:34 +0100176 args['component_driver'], args['component_ref']))
Przemek Stekiel51f30ff2022-11-09 12:07:29 +0100177 return analyze_driver_vs_reference(outcomes, args['component_ref'],
Valerio Setti3002c992023-01-18 17:28:36 +0100178 args['component_driver'], ignored_suites,
179 args['ignored_tests'])
Gilles Peskine15c2cbf2020-06-25 18:36:28 +0200180
Przemek Stekiel6856f4c2022-11-09 10:50:29 +0100181# List of tasks with a function that can handle this task and additional arguments if required
Przemek Stekiel4d13c832022-10-26 16:11:26 +0200182TASKS = {
183 'analyze_coverage': {
184 'test_function': do_analyze_coverage,
Tomás González07bdcc22023-08-11 14:59:03 +0100185 'args': {
Tomás González358c6c62023-08-14 15:43:46 +0100186 'allow_list': [
Tomás González50223112023-08-22 09:52:06 +0100187 # Algorithm not supported yet
188 'test_suite_psa_crypto_metadata;Asymmetric signature: pure EdDSA',
189 # Algorithm not supported yet
190 'test_suite_psa_crypto_metadata;Cipher: XTS',
Tomás González358c6c62023-08-14 15:43:46 +0100191 ],
Tomás Gonzálezb401e112023-08-11 15:22:04 +0100192 'full_coverage': False,
Tomás González07bdcc22023-08-11 14:59:03 +0100193 }
Manuel Pégourié-Gonnard10e39632022-12-29 12:29:09 +0100194 },
Valerio Settia2663322023-03-24 08:20:18 +0100195 # There are 2 options to use analyze_driver_vs_reference_xxx locally:
196 # 1. Run tests and then analysis:
197 # - tests/scripts/all.sh --outcome-file "$PWD/out.csv" <component_ref> <component_driver>
198 # - tests/scripts/analyze_outcomes.py out.csv analyze_driver_vs_reference_xxx
199 # 2. Let this script run both automatically:
200 # - tests/scripts/analyze_outcomes.py out.csv analyze_driver_vs_reference_xxx
Przemek Stekiel4d13c832022-10-26 16:11:26 +0200201 'analyze_driver_vs_reference_hash': {
202 'test_function': do_analyze_driver_vs_reference,
203 'args': {
Przemek Stekiel51f30ff2022-11-09 12:07:29 +0100204 'component_ref': 'test_psa_crypto_config_reference_hash_use_psa',
205 'component_driver': 'test_psa_crypto_config_accel_hash_use_psa',
Manuel Pégourié-Gonnard10e39632022-12-29 12:29:09 +0100206 'ignored_suites': [
207 'shax', 'mdx', # the software implementations that are being excluded
Manuel Pégourié-Gonnard7d381f52023-03-17 15:13:08 +0100208 'md.psa', # purposefully depends on whether drivers are present
Valerio Setti3002c992023-01-18 17:28:36 +0100209 ],
210 'ignored_tests': {
211 }
212 }
213 },
Valerio Setti4d25a8d2023-06-14 10:33:10 +0200214 'analyze_driver_vs_reference_ecp_light_only': {
Valerio Setti42d5f192023-03-20 13:54:41 +0100215 'test_function': do_analyze_driver_vs_reference,
216 'args': {
Valerio Setti4d25a8d2023-06-14 10:33:10 +0200217 'component_ref': 'test_psa_crypto_config_reference_ecc_ecp_light_only',
218 'component_driver': 'test_psa_crypto_config_accel_ecc_ecp_light_only',
Valerio Setti42d5f192023-03-20 13:54:41 +0100219 'ignored_suites': [
220 'ecdsa',
221 'ecdh',
222 'ecjpake',
223 ],
224 'ignored_tests': {
225 'test_suite_random': [
226 'PSA classic wrapper: ECDSA signature (SECP256R1)',
227 ],
Valerio Setti0c477d32023-04-07 15:54:20 +0200228 # In the accelerated test ECP_C is not set (only ECP_LIGHT is)
229 # so we must ignore disparities in the tests for which ECP_C
230 # is required.
231 'test_suite_ecp': [
232 'ECP check public-private #1 (OK)',
233 'ECP check public-private #2 (group none)',
234 'ECP check public-private #3 (group mismatch)',
235 'ECP check public-private #4 (Qx mismatch)',
236 'ECP check public-private #5 (Qy mismatch)',
237 'ECP check public-private #6 (wrong Qx)',
238 'ECP check public-private #7 (wrong Qy)',
239 'ECP gen keypair [#1]',
240 'ECP gen keypair [#2]',
241 'ECP gen keypair [#3]',
242 'ECP gen keypair wrapper',
243 'ECP point muladd secp256r1 #1',
244 'ECP point muladd secp256r1 #2',
245 'ECP point multiplication Curve25519 (element of order 2: origin) #3',
246 'ECP point multiplication Curve25519 (element of order 4: 1) #4',
247 'ECP point multiplication Curve25519 (element of order 8) #5',
248 'ECP point multiplication Curve25519 (normalized) #1',
249 'ECP point multiplication Curve25519 (not normalized) #2',
250 'ECP point multiplication rng fail Curve25519',
251 'ECP point multiplication rng fail secp256r1',
252 'ECP test vectors Curve25519',
253 'ECP test vectors Curve448 (RFC 7748 6.2, after decodeUCoordinate)',
254 'ECP test vectors brainpoolP256r1 rfc 7027',
255 'ECP test vectors brainpoolP384r1 rfc 7027',
256 'ECP test vectors brainpoolP512r1 rfc 7027',
257 'ECP test vectors secp192k1',
258 'ECP test vectors secp192r1 rfc 5114',
259 'ECP test vectors secp224k1',
260 'ECP test vectors secp224r1 rfc 5114',
261 'ECP test vectors secp256k1',
262 'ECP test vectors secp256r1 rfc 5114',
263 'ECP test vectors secp384r1 rfc 5114',
264 'ECP test vectors secp521r1 rfc 5114',
Valerio Settie50a75f2023-05-19 17:43:06 +0200265 ],
Valerio Setti5f540202023-06-30 17:20:49 +0200266 }
Valerio Setti42d5f192023-03-20 13:54:41 +0100267 }
268 },
Valerio Setti4d25a8d2023-06-14 10:33:10 +0200269 'analyze_driver_vs_reference_no_ecp_at_all': {
Valerio Settie618cb02023-04-12 14:59:16 +0200270 'test_function': do_analyze_driver_vs_reference,
271 'args': {
Valerio Setti4d25a8d2023-06-14 10:33:10 +0200272 'component_ref': 'test_psa_crypto_config_reference_ecc_no_ecp_at_all',
273 'component_driver': 'test_psa_crypto_config_accel_ecc_no_ecp_at_all',
Valerio Settie618cb02023-04-12 14:59:16 +0200274 'ignored_suites': [
275 # Ignore test suites for the modules that are disabled in the
276 # accelerated test case.
277 'ecp',
278 'ecdsa',
279 'ecdh',
280 'ecjpake',
281 ],
282 'ignored_tests': {
283 'test_suite_random': [
284 'PSA classic wrapper: ECDSA signature (SECP256R1)',
285 ],
286 'test_suite_psa_crypto': [
287 'PSA key derivation: HKDF-SHA-256 -> ECC secp256r1',
288 'PSA key derivation: HKDF-SHA-256 -> ECC secp256r1 (1 redraw)',
289 'PSA key derivation: HKDF-SHA-256 -> ECC secp256r1, exercise ECDSA',
290 'PSA key derivation: HKDF-SHA-256 -> ECC secp384r1',
291 'PSA key derivation: HKDF-SHA-256 -> ECC secp521r1 #0',
292 'PSA key derivation: HKDF-SHA-256 -> ECC secp521r1 #1',
293 'PSA key derivation: bits=7 invalid for ECC BRAINPOOL_P_R1 (ECC enabled)',
294 'PSA key derivation: bits=7 invalid for ECC SECP_K1 (ECC enabled)',
295 'PSA key derivation: bits=7 invalid for ECC SECP_R1 (ECC enabled)',
296 'PSA key derivation: bits=7 invalid for ECC SECP_R2 (ECC enabled)',
297 'PSA key derivation: bits=7 invalid for ECC SECT_K1 (ECC enabled)',
298 'PSA key derivation: bits=7 invalid for ECC SECT_R1 (ECC enabled)',
299 'PSA key derivation: bits=7 invalid for ECC SECT_R2 (ECC enabled)',
Valerio Settiaddeee42023-06-14 10:46:55 +0200300 ],
301 'test_suite_pkparse': [
Valerio Setti5bd25232023-06-19 19:32:14 +0200302 # When PK_PARSE_C and ECP_C are defined then PK_PARSE_EC_COMPRESSED
303 # is automatically enabled in build_info.h (backward compatibility)
304 # even if it is disabled in config_psa_crypto_no_ecp_at_all(). As a
305 # consequence compressed points are supported in the reference
306 # component but not in the accelerated one, so they should be skipped
307 # while checking driver's coverage.
308 'Parse EC Key #10a (SEC1 PEM, secp384r1, compressed)',
309 'Parse EC Key #11a (SEC1 PEM, secp521r1, compressed)',
310 'Parse EC Key #12a (SEC1 PEM, bp256r1, compressed)',
311 'Parse EC Key #13a (SEC1 PEM, bp384r1, compressed)',
312 'Parse EC Key #14a (SEC1 PEM, bp512r1, compressed)',
313 'Parse EC Key #2a (SEC1 PEM, secp192r1, compressed)',
314 'Parse EC Key #8a (SEC1 PEM, secp224r1, compressed)',
315 'Parse EC Key #9a (SEC1 PEM, secp256r1, compressed)',
316 'Parse Public EC Key #2a (RFC 5480, PEM, secp192r1, compressed)',
317 'Parse Public EC Key #3a (RFC 5480, secp224r1, compressed)',
318 'Parse Public EC Key #4a (RFC 5480, secp256r1, compressed)',
319 'Parse Public EC Key #5a (RFC 5480, secp384r1, compressed)',
320 'Parse Public EC Key #6a (RFC 5480, secp521r1, compressed)',
321 'Parse Public EC Key #7a (RFC 5480, brainpoolP256r1, compressed)',
322 'Parse Public EC Key #8a (RFC 5480, brainpoolP384r1, compressed)',
323 'Parse Public EC Key #9a (RFC 5480, brainpoolP512r1, compressed)',
Valerio Settiaddeee42023-06-14 10:46:55 +0200324 ],
Valerio Settie618cb02023-04-12 14:59:16 +0200325 }
326 }
327 },
Manuel Pégourié-Gonnardabd00d02023-06-12 17:51:33 +0200328 'analyze_driver_vs_reference_no_bignum': {
329 'test_function': do_analyze_driver_vs_reference,
330 'args': {
331 'component_ref': 'test_psa_crypto_config_reference_ecc_no_bignum',
332 'component_driver': 'test_psa_crypto_config_accel_ecc_no_bignum',
333 'ignored_suites': [
334 # Ignore test suites for the modules that are disabled in the
335 # accelerated test case.
336 'ecp',
337 'ecdsa',
338 'ecdh',
339 'ecjpake',
Valerio Setti9b3dbcc2023-07-26 18:00:31 +0200340 'bignum_core',
341 'bignum_random',
342 'bignum_mod',
343 'bignum_mod_raw',
344 'bignum.generated',
345 'bignum.misc',
Manuel Pégourié-Gonnardabd00d02023-06-12 17:51:33 +0200346 ],
347 'ignored_tests': {
348 'test_suite_random': [
349 'PSA classic wrapper: ECDSA signature (SECP256R1)',
350 ],
351 'test_suite_psa_crypto': [
352 'PSA key derivation: HKDF-SHA-256 -> ECC secp256r1',
353 'PSA key derivation: HKDF-SHA-256 -> ECC secp256r1 (1 redraw)',
354 'PSA key derivation: HKDF-SHA-256 -> ECC secp256r1, exercise ECDSA',
355 'PSA key derivation: HKDF-SHA-256 -> ECC secp384r1',
356 'PSA key derivation: HKDF-SHA-256 -> ECC secp521r1 #0',
357 'PSA key derivation: HKDF-SHA-256 -> ECC secp521r1 #1',
358 'PSA key derivation: bits=7 invalid for ECC BRAINPOOL_P_R1 (ECC enabled)',
359 'PSA key derivation: bits=7 invalid for ECC SECP_K1 (ECC enabled)',
360 'PSA key derivation: bits=7 invalid for ECC SECP_R1 (ECC enabled)',
361 'PSA key derivation: bits=7 invalid for ECC SECP_R2 (ECC enabled)',
362 'PSA key derivation: bits=7 invalid for ECC SECT_K1 (ECC enabled)',
363 'PSA key derivation: bits=7 invalid for ECC SECT_R1 (ECC enabled)',
364 'PSA key derivation: bits=7 invalid for ECC SECT_R2 (ECC enabled)',
365 ],
366 'test_suite_pkparse': [
367 # See the description provided above in the
368 # analyze_driver_vs_reference_no_ecp_at_all component.
369 'Parse EC Key #10a (SEC1 PEM, secp384r1, compressed)',
370 'Parse EC Key #11a (SEC1 PEM, secp521r1, compressed)',
371 'Parse EC Key #12a (SEC1 PEM, bp256r1, compressed)',
372 'Parse EC Key #13a (SEC1 PEM, bp384r1, compressed)',
373 'Parse EC Key #14a (SEC1 PEM, bp512r1, compressed)',
374 'Parse EC Key #2a (SEC1 PEM, secp192r1, compressed)',
375 'Parse EC Key #8a (SEC1 PEM, secp224r1, compressed)',
376 'Parse EC Key #9a (SEC1 PEM, secp256r1, compressed)',
377 'Parse Public EC Key #2a (RFC 5480, PEM, secp192r1, compressed)',
378 'Parse Public EC Key #3a (RFC 5480, secp224r1, compressed)',
379 'Parse Public EC Key #4a (RFC 5480, secp256r1, compressed)',
380 'Parse Public EC Key #5a (RFC 5480, secp384r1, compressed)',
381 'Parse Public EC Key #6a (RFC 5480, secp521r1, compressed)',
382 'Parse Public EC Key #7a (RFC 5480, brainpoolP256r1, compressed)',
383 'Parse Public EC Key #8a (RFC 5480, brainpoolP384r1, compressed)',
384 'Parse Public EC Key #9a (RFC 5480, brainpoolP512r1, compressed)',
385 ],
Valerio Setti9b3dbcc2023-07-26 18:00:31 +0200386 'test_suite_asn1parse': [
387 # This test depends on BIGNUM_C
388 'INTEGER too large for mpi',
389 ],
390 'test_suite_asn1write': [
391 # Following tests depends on BIGNUM_C
392 'ASN.1 Write mpi 0 (1 limb)',
393 'ASN.1 Write mpi 0 (null)',
394 'ASN.1 Write mpi 0x100',
395 'ASN.1 Write mpi 0x7f',
396 'ASN.1 Write mpi 0x7f with leading 0 limb',
397 'ASN.1 Write mpi 0x80',
398 'ASN.1 Write mpi 0x80 with leading 0 limb',
399 'ASN.1 Write mpi 0xff',
400 'ASN.1 Write mpi 1',
401 'ASN.1 Write mpi, 127*8 bits',
402 'ASN.1 Write mpi, 127*8+1 bits',
403 'ASN.1 Write mpi, 127*8-1 bits',
404 'ASN.1 Write mpi, 255*8 bits',
405 'ASN.1 Write mpi, 255*8-1 bits',
406 'ASN.1 Write mpi, 256*8-1 bits',
407 ],
Valerio Settie0be95e2023-08-01 09:07:43 +0200408 'test_suite_debug': [
409 # Following tests depends on BIGNUM_C
410 'Debug print mbedtls_mpi #2: 3 bits',
411 'Debug print mbedtls_mpi: 0 (empty representation)',
412 'Debug print mbedtls_mpi: 0 (non-empty representation)',
413 'Debug print mbedtls_mpi: 49 bits',
414 'Debug print mbedtls_mpi: 759 bits',
415 'Debug print mbedtls_mpi: 764 bits #1',
416 'Debug print mbedtls_mpi: 764 bits #2',
417 ],
Manuel Pégourié-Gonnardabd00d02023-06-12 17:51:33 +0200418 }
419 }
420 },
Przemek Stekiel85b64422023-05-26 09:55:23 +0200421 'analyze_driver_vs_reference_ffdh_alg': {
422 'test_function': do_analyze_driver_vs_reference,
423 'args': {
424 'component_ref': 'test_psa_crypto_config_reference_ffdh',
425 'component_driver': 'test_psa_crypto_config_accel_ffdh',
Przemek Stekiel84f4ff12023-07-04 12:35:31 +0200426 'ignored_suites': ['dhm'],
Przemek Stekiel565353e2023-07-05 11:07:07 +0200427 'ignored_tests': {}
Przemek Stekiel85b64422023-05-26 09:55:23 +0200428 }
429 },
Przemek Stekiel4d13c832022-10-26 16:11:26 +0200430}
Przemek Stekiel4d13c832022-10-26 16:11:26 +0200431
Gilles Peskine15c2cbf2020-06-25 18:36:28 +0200432def main():
433 try:
434 parser = argparse.ArgumentParser(description=__doc__)
Przemek Stekiel58bbc232022-10-24 08:10:10 +0200435 parser.add_argument('outcomes', metavar='OUTCOMES.CSV',
Gilles Peskine15c2cbf2020-06-25 18:36:28 +0200436 help='Outcome file to analyze')
Przemek Stekiel542d9322022-11-17 09:43:34 +0100437 parser.add_argument('task', default='all', nargs='?',
Przemek Stekiel992de3c2022-11-09 13:54:49 +0100438 help='Analysis to be done. By default, run all tasks. '
439 'With one or more TASK, run only those. '
440 'TASK can be the name of a single task or '
Przemek Stekiel85c54ea2022-11-17 11:50:23 +0100441 'comma/space-separated list of tasks. ')
Przemek Stekiel992de3c2022-11-09 13:54:49 +0100442 parser.add_argument('--list', action='store_true',
443 help='List all available tasks and exit.')
Tomás Gonzálezb401e112023-08-11 15:22:04 +0100444 parser.add_argument('--require-full-coverage', action='store_true',
445 dest='full_coverage', help="Require all available "
446 "test cases to be executed and issue an error "
447 "otherwise. This flag is ignored if 'task' is "
448 "neither 'all' nor 'analyze_coverage'")
Gilles Peskine15c2cbf2020-06-25 18:36:28 +0200449 options = parser.parse_args()
Przemek Stekiel4e955902022-10-21 13:42:08 +0200450
Przemek Stekiel992de3c2022-11-09 13:54:49 +0100451 if options.list:
452 for task in TASKS:
Valerio Setti3951d1b2023-03-13 18:37:34 +0100453 Results.log(task)
Przemek Stekiel992de3c2022-11-09 13:54:49 +0100454 sys.exit(0)
455
Przemek Stekiel4d13c832022-10-26 16:11:26 +0200456 result = True
Przemek Stekiel4e955902022-10-21 13:42:08 +0200457
Przemek Stekiel4d13c832022-10-26 16:11:26 +0200458 if options.task == 'all':
Przemek Stekield3068af2022-11-14 16:15:19 +0100459 tasks = TASKS.keys()
Przemek Stekiel992de3c2022-11-09 13:54:49 +0100460 else:
Przemek Stekiel85c54ea2022-11-17 11:50:23 +0100461 tasks = re.split(r'[, ]+', options.task)
Przemek Stekiel992de3c2022-11-09 13:54:49 +0100462
Przemek Stekield3068af2022-11-14 16:15:19 +0100463 for task in tasks:
464 if task not in TASKS:
Valerio Setti3951d1b2023-03-13 18:37:34 +0100465 Results.log('Error: invalid task: {}'.format(task))
Przemek Stekield3068af2022-11-14 16:15:19 +0100466 sys.exit(1)
Przemek Stekiel992de3c2022-11-09 13:54:49 +0100467
Tomás Gonzálezb401e112023-08-11 15:22:04 +0100468 TASKS['analyze_coverage']['args']['full_coverage'] = \
469 options.full_coverage
470
Przemek Stekiel992de3c2022-11-09 13:54:49 +0100471 for task in TASKS:
472 if task in tasks:
Przemek Stekiel4d13c832022-10-26 16:11:26 +0200473 if not TASKS[task]['test_function'](options.outcomes, TASKS[task]['args']):
474 result = False
Przemek Stekiel4e955902022-10-21 13:42:08 +0200475
Przemek Stekielc86dedf2022-10-24 09:16:04 +0200476 if result is False:
Gilles Peskine15c2cbf2020-06-25 18:36:28 +0200477 sys.exit(1)
Valerio Setti3951d1b2023-03-13 18:37:34 +0100478 Results.log("SUCCESS :-)")
Gilles Peskine15c2cbf2020-06-25 18:36:28 +0200479 except Exception: # pylint: disable=broad-except
480 # Print the backtrace and exit explicitly with our chosen status.
481 traceback.print_exc()
482 sys.exit(120)
483
484if __name__ == '__main__':
485 main()