Skip to content

Commit 668f9df

Browse files
timothytrippelpamaury
authored andcommitted
[rom_ext,e2e] add ROM_EXT E2E test to check variation interoperability
There are two flavors of ROM_EXT: 1. one that uses X.509 DICE cert encodings, and 2. one that uses CWT DICE cert encodings. If you run one first, you should be able to run the other later and the ROM_EXT should seemlessly update the CDI certs. This adds a test to check this behavior works as intended. Signed-off-by: Tim Trippel <[email protected]> (cherry picked from commit 8a2ac65)
1 parent 9ec564a commit 668f9df

File tree

4 files changed

+219
-1
lines changed

4 files changed

+219
-1
lines changed

sw/device/silicon_creator/lib/cert/dice_chain.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ rom_error_t dice_chain_attestation_owner(
437437
// Check if the current CDI_1 cert is valid.
438438
RETURN_IF_ERROR(dice_chain_load_cert_obj("CDI_1", /*name_size=*/6));
439439
if (dice_chain.cert_valid == kHardenedBoolFalse) {
440-
dbg_puts("CDI_1 certificate not valid. Updating it ...\r\n");
440+
dbg_puts("warning: CDI_1 certificate not valid; Updating it ...\r\n");
441441
// Update the cert page buffer.
442442
size_t updated_cert_size = kScratchCertSizeBytes;
443443
// TODO(#19596): add owner configuration block measurement to CDI_1 cert.

sw/device/silicon_creator/rom_ext/e2e/dice_chain/BUILD

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,27 @@
22
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
33
# SPDX-License-Identifier: Apache-2.0
44

5+
load("//rules:const.bzl", "CONST", "hex")
6+
load("//rules:manifest.bzl", "manifest")
7+
load("//rules/opentitan:cc.bzl", "opentitan_binary_assemble")
58
load(
69
"//rules/opentitan:defs.bzl",
710
"fpga_params",
11+
"opentitan_binary",
812
"opentitan_test",
913
)
14+
load(
15+
"//sw/device/silicon_creator/rom/e2e:defs.bzl",
16+
"SLOTS",
17+
)
1018
load(
1119
"//sw/device/silicon_creator/rom_ext:defs.bzl",
1220
"ROM_EXT_VARIATIONS",
1321
)
22+
load(
23+
"//sw/device/silicon_creator/rom_ext/e2e:defs.bzl",
24+
"OWNER_SLOTS",
25+
)
1426

1527
package(default_visibility = ["//visibility:public"])
1628

@@ -38,3 +50,91 @@ package(default_visibility = ["//visibility:public"])
3850
)
3951
for variation in ROM_EXT_VARIATIONS.keys()
4052
]
53+
54+
manifest({
55+
"name": "owner_manifest",
56+
"identifier": hex(CONST.OWNER),
57+
"visibility": ["//visibility:private"],
58+
})
59+
60+
opentitan_binary(
61+
name = "print_certs_for_assemble",
62+
testonly = True,
63+
srcs = ["//sw/device/silicon_creator/rom_ext/e2e/attestation:print_certs.c"],
64+
exec_env = {
65+
"//hw/top_earlgrey:fpga_cw310_rom_ext": None,
66+
"//hw/top_earlgrey:fpga_cw340_rom_ext": None,
67+
},
68+
linker_script = "//sw/device/lib/testing/test_framework:ottf_ld_silicon_owner_slot_a",
69+
manifest = ":owner_manifest",
70+
deps = [
71+
"//sw/device/lib/base:status",
72+
"//sw/device/lib/runtime:log",
73+
"//sw/device/lib/runtime:print",
74+
"//sw/device/lib/testing/test_framework:ottf_main",
75+
"//sw/device/silicon_creator/lib/drivers:flash_ctrl",
76+
"//sw/device/silicon_creator/manuf/base:perso_tlv_data",
77+
],
78+
)
79+
80+
[
81+
opentitan_binary_assemble(
82+
name = "{}_rom_ext_owner_bundle".format(variation),
83+
testonly = True,
84+
bins = {
85+
"//sw/device/silicon_creator/rom_ext:rom_ext_{}_slot_a".format(variation): SLOTS["a"],
86+
":print_certs_for_assemble": OWNER_SLOTS["a"],
87+
},
88+
exec_env = [
89+
"//hw/top_earlgrey:fpga_cw310_rom_with_fake_keys",
90+
"//hw/top_earlgrey:fpga_cw340_rom_with_fake_keys",
91+
],
92+
)
93+
for variation in ROM_EXT_VARIATIONS.keys()
94+
]
95+
96+
_VARIATION_INTEROP_TEST_CASES = [
97+
{
98+
"first": "x509",
99+
"second": "cwt",
100+
},
101+
{
102+
"first": "cwt",
103+
"second": "x509",
104+
},
105+
]
106+
107+
[
108+
opentitan_test(
109+
name = "variation_interop_{}_first_test".format(tc["first"]),
110+
exec_env = {
111+
"//hw/top_earlgrey:fpga_cw310_rom_with_fake_keys": None,
112+
"//hw/top_earlgrey:fpga_cw340_rom_with_fake_keys": None,
113+
},
114+
fpga = fpga_params(
115+
binaries = {
116+
":dice_{}_rom_ext_owner_bundle".format(tc["second"]): "second",
117+
":dice_{}_rom_ext_owner_bundle".format(tc["first"]): "firmware",
118+
},
119+
otp = "//sw/device/silicon_creator/rom_ext/e2e:otp_img_secret2_locked_rma",
120+
test_cmd = """
121+
--clear-bitstream
122+
--bootstrap={firmware}
123+
--second-bootstrap={second}
124+
""",
125+
test_harness = "//sw/host/tests/rom_ext/e2e_variation_interop",
126+
),
127+
)
128+
for tc in _VARIATION_INTEROP_TEST_CASES
129+
]
130+
131+
test_suite(
132+
name = "variation_interop_tests",
133+
tags = ["manual"],
134+
tests = [
135+
"variation_interop_{}_first_test".format(
136+
tc["first"],
137+
)
138+
for tc in _VARIATION_INTEROP_TEST_CASES
139+
],
140+
)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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+
load("@rules_rust//rust:defs.bzl", "rust_binary")
6+
7+
package(default_visibility = ["//visibility:public"])
8+
9+
rust_binary(
10+
name = "e2e_variation_interop",
11+
srcs = [
12+
"src/main.rs",
13+
],
14+
deps = [
15+
"//sw/host/opentitanlib",
16+
"//third_party/rust/crates:anyhow",
17+
"//third_party/rust/crates:clap",
18+
"//third_party/rust/crates:humantime",
19+
"//third_party/rust/crates:log",
20+
"//third_party/rust/crates:num_enum",
21+
"//third_party/rust/crates:regex",
22+
],
23+
)
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
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+
//! ROM_EXT E2E Variation Interoperability test.
6+
//!
7+
//! This test harness checks that an CWT ROM_EXT can be booted on a chip before and after an X.509
8+
//! ROM_EXT can be booted, and vice versa. In both cases, CDI_* should be regenerated by the
9+
//! ROM_EXT seamlessly.
10+
11+
use std::path::PathBuf;
12+
use std::time::Duration;
13+
14+
use anyhow::{anyhow, Context};
15+
use clap::Parser;
16+
use regex::Regex;
17+
18+
use opentitanlib::test_utils::init::InitializeTest;
19+
use opentitanlib::uart::console::{ExitStatus, UartConsole};
20+
21+
/// CLI args for this test.
22+
#[derive(Debug, Parser)]
23+
struct Opts {
24+
#[command(flatten)]
25+
init: InitializeTest,
26+
27+
/// Second image (ROM_EXT + Owner FW bundle) to bootstrap.
28+
#[arg(long)]
29+
second_bootstrap: PathBuf,
30+
31+
/// Console receive timeout.
32+
#[arg(long, value_parser = humantime::parse_duration, default_value = "30s")]
33+
timeout: Duration,
34+
}
35+
36+
fn main() -> anyhow::Result<()> {
37+
let opts = Opts::parse();
38+
opts.init.init_logging();
39+
40+
// Bootstrap first ROM_EXT + Owner FW.
41+
let transport = opts.init.init_target()?;
42+
let uart = transport.uart("console").context("failed to get UART")?;
43+
44+
// Wait for CDI_* update messags.
45+
for i in 0..2 {
46+
let _ = UartConsole::wait_for(
47+
&*uart,
48+
format!(r"warning: CDI_{:?} certificate not valid; updating", i).as_str(),
49+
opts.timeout,
50+
)?;
51+
}
52+
53+
// Wait for pass message from first owner firmware stage.
54+
let _ = UartConsole::wait_for(&*uart, r"PASS!", opts.timeout)?;
55+
56+
// Bootstrap second ROM_EXT + Owner FW.
57+
opts.init
58+
.bootstrap
59+
.load(&transport, &opts.second_bootstrap)?;
60+
61+
// Wait for pass message from owner firmware stage.
62+
let mut console = UartConsole {
63+
timeout: Some(opts.timeout),
64+
exit_success: Some(Regex::new(r"PASS.*\n")?),
65+
exit_failure: Some(Regex::new(r"BFV.*\n")?),
66+
newline: true,
67+
..Default::default()
68+
};
69+
let mut stdout = std::io::stdout();
70+
let result = console.interact(&*uart, None, Some(&mut stdout))?;
71+
match result {
72+
ExitStatus::None | ExitStatus::CtrlC => Ok(()),
73+
ExitStatus::Timeout => {
74+
if console.exit_success.is_some() {
75+
Err(anyhow!("Console timeout exceeded"))
76+
} else {
77+
Ok(())
78+
}
79+
}
80+
ExitStatus::ExitSuccess => {
81+
log::info!(
82+
"ExitSuccess({:?})",
83+
console.captures(result).unwrap().get(0).unwrap().as_str()
84+
);
85+
Ok(())
86+
}
87+
ExitStatus::ExitFailure => {
88+
log::info!(
89+
"ExitFailure({:?})",
90+
console.captures(result).unwrap().get(0).unwrap().as_str()
91+
);
92+
Err(anyhow!("Matched exit_failure expression"))
93+
}
94+
}
95+
}

0 commit comments

Comments
 (0)