Skip to content

Commit a069a52

Browse files
siemen11nasahlpa
authored andcommitted
[pentest] Add RNG tests for ESV and CC eval
For certification, the RNG sources need to be tested in conditions like extreme temperatures or with fw overide access. The RNG sources for OpenTitan consist of the TRNG which is the entropy source which has no direct access and the CSRNG acting as DRBG which is seeded by the TRNG. Since CC and FIPS require different tests, we provide two separate scripts to test their requirements. Signed-off-by: Siemen Dhooghe <sdhooghe@google.com>
1 parent a5718d8 commit a069a52

4 files changed

Lines changed: 436 additions & 0 deletions

File tree

sw/device/tests/penetrationtests/BUILD

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,24 @@ pentest_owner_upgrade_self_signed_fi_gdb(
567567
test_vectors = [],
568568
)
569569

570+
# RNG test for certification, this is a manual tests
571+
pentest_cryptolib_fi_sym(
572+
name = "cc_rng_output_test",
573+
tags = ["manual"],
574+
test_args = "",
575+
test_harness = "//sw/host/penetrationtests/python/fi:cc_rng_output_test",
576+
test_vectors = [],
577+
)
578+
579+
# RNG test for certification, this is a manual tests
580+
pentest_fi(
581+
name = "fips_rng_output_test",
582+
tags = ["manual"],
583+
test_args = "",
584+
test_harness = "//sw/host/penetrationtests/python/fi:fips_rng_output_test",
585+
test_vectors = [],
586+
)
587+
570588
genrule(
571589
name = "doxygen",
572590
srcs = [

sw/host/penetrationtests/python/fi/BUILD

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,34 @@ py_binary(
379379
],
380380
)
381381

382+
py_binary(
383+
name = "cc_rng_output_test",
384+
testonly = True,
385+
srcs = ["test_scripts/cc_rng_output_test.py"],
386+
data = [
387+
"//sw/host/opentitantool",
388+
],
389+
deps = [
390+
"//sw/host/penetrationtests/python/fi:fi_sym_cryptolib_commands",
391+
"//sw/host/penetrationtests/python/util:targets",
392+
"@rules_python//python/runfiles",
393+
],
394+
)
395+
396+
py_binary(
397+
name = "fips_rng_output_test",
398+
testonly = True,
399+
srcs = ["test_scripts/fips_rng_output_test.py"],
400+
data = [
401+
"//sw/host/opentitantool",
402+
],
403+
deps = [
404+
"//sw/host/penetrationtests/python/fi:fi_rng_commands",
405+
"//sw/host/penetrationtests/python/util:targets",
406+
"@rules_python//python/runfiles",
407+
],
408+
)
409+
382410
py_library(
383411
name = "fi_ibex_functions",
384412
srcs = ["host_scripts/fi_ibex_functions.py"],
Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
# Copyright lowRISC contributors (OpenTitan project).
2+
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
from sw.host.penetrationtests.python.fi.communication.fi_sym_cryptolib_commands import (
6+
OTFISymCrypto,
7+
)
8+
from python.runfiles import Runfiles
9+
from sw.host.penetrationtests.python.util import targets
10+
import json
11+
import unittest
12+
import argparse
13+
import sys
14+
import os
15+
16+
opentitantool_path = ""
17+
target = None
18+
19+
# Read in the extra arguments from the opentitan_test.
20+
parser = argparse.ArgumentParser()
21+
parser.add_argument("--bitstream", type=str)
22+
parser.add_argument("--bootstrap", type=str)
23+
parser.add_argument("--data_size", type=int, default=640000)
24+
25+
args, config_args = parser.parse_known_args()
26+
27+
BITSTREAM = args.bitstream
28+
BOOTSTRAP = args.bootstrap
29+
30+
OUTPUT_DIR_VAR = "TEST_UNDECLARED_OUTPUTS_DIR"
31+
output_dir = None
32+
33+
34+
class CCRngTest(unittest.TestCase):
35+
def test_drbg_output(self):
36+
# Absolute file path
37+
output_file_path = os.path.join(output_dir, "cc_drbg_output.bin")
38+
39+
symfi = OTFISymCrypto(target)
40+
target.reset_target()
41+
# Clear the output from the reset
42+
target.dump_all()
43+
44+
print()
45+
print(
46+
"Starting the DRBG output test for CC, the following is the chip state",
47+
flush=True,
48+
)
49+
print()
50+
(
51+
device_id,
52+
sensors,
53+
alerts,
54+
owner_page,
55+
boot_log,
56+
boot_measurements,
57+
version,
58+
cryptolib_version,
59+
) = symfi.init()
60+
print(device_id)
61+
print(sensors)
62+
print(alerts)
63+
print(owner_page)
64+
print(boot_log)
65+
print(boot_measurements)
66+
print(version)
67+
print(cryptolib_version)
68+
69+
print()
70+
print("Performing the cryptolib TRNG init", flush=True)
71+
print()
72+
symfi.handle_trng_init(0, 0, 0)
73+
response = target.read_response()
74+
response_dict = json.loads(response)
75+
self.assertEqual(
76+
response_dict["status"],
77+
0,
78+
f"Status error in handle_trng_init: {response}",
79+
)
80+
self.assertEqual(
81+
response_dict["err_status"],
82+
0,
83+
f"Error status in handle_trng_init: {response}",
84+
)
85+
self.assertEqual(
86+
response_dict["loc_alerts"],
87+
0,
88+
f"Local alerts in handle_trng_init: {response}",
89+
)
90+
alerts = response_dict["alerts"]
91+
all_alerts_zero = all(alert == 0 for alert in alerts)
92+
self.assertTrue(
93+
all_alerts_zero,
94+
f"Alerts in handle_trng_init: {response}",
95+
)
96+
ast_alerts = response_dict["ast_alerts"]
97+
all_ast_alerts_zero = all(alert == 0 for alert in ast_alerts)
98+
self.assertTrue(
99+
all_ast_alerts_zero,
100+
f"AST alerts in handle_trng_init: {response}",
101+
)
102+
print(response)
103+
104+
print(
105+
"Calling the DRBG reseed without personalization",
106+
flush=True,
107+
)
108+
symfi.handle_drbg_reseed([], 0, [], 0, 0, 0, 0, 0)
109+
response = target.read_response()
110+
response_dict = json.loads(response)
111+
self.assertEqual(
112+
response_dict["status"],
113+
0,
114+
f"Status error in handle_drbg_reseed: {response}",
115+
)
116+
self.assertEqual(
117+
response_dict["err_status"],
118+
0,
119+
f"Error status in handle_drbg_reseed: {response}",
120+
)
121+
self.assertEqual(
122+
response_dict["loc_alerts"],
123+
0,
124+
f"Local alerts in handle_drbg_reseed: {response}",
125+
)
126+
alerts = response_dict["alerts"]
127+
all_alerts_zero = all(alert == 0 for alert in alerts)
128+
self.assertTrue(
129+
all_alerts_zero,
130+
f"Alerts in handle_drbg_reseed: {response}",
131+
)
132+
ast_alerts = response_dict["ast_alerts"]
133+
all_ast_alerts_zero = all(alert == 0 for alert in ast_alerts)
134+
self.assertTrue(
135+
all_ast_alerts_zero,
136+
f"AST alerts in handle_drbg_reseed: {response}",
137+
)
138+
print(response)
139+
140+
DRBGSIZE = args.data_size // 256
141+
142+
print(
143+
f"We write a total of {DRBGSIZE} times 256 bytes of data.",
144+
flush=True,
145+
)
146+
iterations = DRBGSIZE
147+
with open(output_file_path, "wb") as f:
148+
for _ in range(iterations):
149+
# Generate 256 bytes of data (the max output size)
150+
symfi.handle_drbg_generate([0], 0, 256, 0, 0, 0)
151+
response = target.read_response()
152+
response_dict = json.loads(response)
153+
self.assertEqual(
154+
response_dict["status"],
155+
0,
156+
f"Status error in handle_drbg_generate: {response}",
157+
)
158+
self.assertEqual(
159+
response_dict["err_status"],
160+
0,
161+
f"Error status in handle_drbg_generate: {response}",
162+
)
163+
self.assertEqual(
164+
response_dict["loc_alerts"],
165+
0,
166+
f"Local alerts in handle_drbg_generate: {response}",
167+
)
168+
alerts = response_dict["alerts"]
169+
all_alerts_zero = all(alert == 0 for alert in alerts)
170+
self.assertTrue(
171+
all_alerts_zero,
172+
f"Alerts in handle_drbg_generate: {response}",
173+
)
174+
ast_alerts = response_dict["ast_alerts"]
175+
all_ast_alerts_zero = all(alert == 0 for alert in ast_alerts)
176+
self.assertTrue(
177+
all_ast_alerts_zero,
178+
f"AST alerts in handle_drbg_generate: {response}",
179+
)
180+
data_list = response_dict["data"]
181+
binary_data = bytes(data_list)
182+
f.write(binary_data)
183+
print("Data is logged in ", output_file_path)
184+
print()
185+
print()
186+
187+
188+
if __name__ == "__main__":
189+
r = Runfiles.Create()
190+
191+
# Set the output directory as test output
192+
output_dir = os.environ.get("TEST_UNDECLARED_OUTPUTS_DIR")
193+
# Get the opentitantool path.
194+
opentitantool_path = r.Rlocation(
195+
"lowrisc_opentitan/sw/host/opentitantool/opentitantool"
196+
)
197+
# Program the bitstream for FPGAs.
198+
bitstream_path = None
199+
if BITSTREAM:
200+
bitstream_path = r.Rlocation("lowrisc_opentitan/" + BITSTREAM)
201+
# Get the firmware path.
202+
firmware_path = r.Rlocation("lowrisc_opentitan/" + BOOTSTRAP)
203+
204+
if "fpga" in BOOTSTRAP:
205+
target_type = "fpga"
206+
else:
207+
target_type = "chip"
208+
209+
target_cfg = targets.TargetConfig(
210+
target_type=target_type,
211+
interface_type="hyperdebug",
212+
fw_bin=firmware_path,
213+
opentitantool=opentitantool_path,
214+
bitstream=bitstream_path,
215+
tool_args=config_args,
216+
)
217+
218+
target = targets.Target(target_cfg)
219+
220+
target.initialize_target()
221+
222+
unittest.main(argv=[sys.argv[0]])

0 commit comments

Comments
 (0)