From 2b761020d632d37b5003048ed8bebccd4e61c7f0 Mon Sep 17 00:00:00 2001 From: Brian Fjeldstad Date: Thu, 8 Oct 2026 15:51:11 +0000 Subject: [PATCH 1/8] hostconfig: add optional verity root hash signature device Adds VerityDevice.signature_device_id (Option) to the HostConfiguration API, linking a verity device to an optional partition holding a detached PKCS#7 signature of its root hash. Wires the new link through the storage dependency graph as a new SpecialReferenceKind::VerityRootHashSignatureDevice: enforces homogeneous partition types, and restricts allowed partition types to LinuxGeneric (no DPS GUID exists for this partition role). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../host/storage/storage_graph/builder/partition.rs | 5 +++++ .../config/host/storage/storage_graph/display.rs | 1 + .../src/config/host/storage/storage_graph/node.rs | 13 +++++++++++-- .../config/host/storage/storage_graph/references.rs | 3 +++ .../config/host/storage/storage_graph/rules/mod.rs | 12 ++++++++++++ .../trident_api/src/config/host/storage/verity.rs | 11 +++++++++++ 6 files changed, 43 insertions(+), 2 deletions(-) diff --git a/crates/trident_api/src/config/host/storage/storage_graph/builder/partition.rs b/crates/trident_api/src/config/host/storage/storage_graph/builder/partition.rs index 98ff59b4c6..efd2d5a5ac 100644 --- a/crates/trident_api/src/config/host/storage/storage_graph/builder/partition.rs +++ b/crates/trident_api/src/config/host/storage/storage_graph/builder/partition.rs @@ -35,6 +35,11 @@ impl SpecialReferenceKind { // attributes as the hash device is entirely consumed by the verity // device. SpecialReferenceKind::VerityHashDevice => false, + + // The verity root hash signature device should NOT pass through + // partition attributes either, as it is entirely consumed by the + // verity device. + SpecialReferenceKind::VerityRootHashSignatureDevice => false, } } } diff --git a/crates/trident_api/src/config/host/storage/storage_graph/display.rs b/crates/trident_api/src/config/host/storage/storage_graph/display.rs index a6191e8d0f..44a937fc62 100644 --- a/crates/trident_api/src/config/host/storage/storage_graph/display.rs +++ b/crates/trident_api/src/config/host/storage/storage_graph/display.rs @@ -57,6 +57,7 @@ impl Display for SpecialReferenceKind { match self { Self::VerityDataDevice => write!(f, "verity-data-device"), Self::VerityHashDevice => write!(f, "verity-hash-device"), + Self::VerityRootHashSignatureDevice => write!(f, "verity-root-hash-signature-device"), } } } diff --git a/crates/trident_api/src/config/host/storage/storage_graph/node.rs b/crates/trident_api/src/config/host/storage/storage_graph/node.rs index 2c87cca640..5677f048cf 100644 --- a/crates/trident_api/src/config/host/storage/storage_graph/node.rs +++ b/crates/trident_api/src/config/host/storage/storage_graph/node.rs @@ -144,7 +144,7 @@ impl StorageGraphNode { vec![StorageReference::new_regular(&encrypted_volume.device_id)] } HostConfigBlockDevice::VerityDevice(verity_device) => { - vec![ + let mut refs = vec![ StorageReference::new_special( SpecialReferenceKind::VerityDataDevice, &verity_device.data_device_id, @@ -153,7 +153,16 @@ impl StorageGraphNode { SpecialReferenceKind::VerityHashDevice, &verity_device.hash_device_id, ), - ] + ]; + + if let Some(signature_device_id) = &verity_device.signature_device_id { + refs.push(StorageReference::new_special( + SpecialReferenceKind::VerityRootHashSignatureDevice, + signature_device_id, + )); + } + + refs } }, Self::FileSystem(fs) => fs diff --git a/crates/trident_api/src/config/host/storage/storage_graph/references.rs b/crates/trident_api/src/config/host/storage/storage_graph/references.rs index 7cf67da0c5..98d49c8411 100644 --- a/crates/trident_api/src/config/host/storage/storage_graph/references.rs +++ b/crates/trident_api/src/config/host/storage/storage_graph/references.rs @@ -29,6 +29,9 @@ pub enum SpecialReferenceKind { /// A reference to a Verity device's underlying hash device. VerityHashDevice, + + /// A reference to a Verity device's root hash signature device. + VerityRootHashSignatureDevice, } /// A reference to a block device in the configuration. diff --git a/crates/trident_api/src/config/host/storage/storage_graph/rules/mod.rs b/crates/trident_api/src/config/host/storage/storage_graph/rules/mod.rs index 2e234c8ec0..12facab027 100644 --- a/crates/trident_api/src/config/host/storage/storage_graph/rules/mod.rs +++ b/crates/trident_api/src/config/host/storage/storage_graph/rules/mod.rs @@ -217,6 +217,10 @@ impl SpecialReferenceKind { // Verity data/hash do not impose any additional restrictions. Self::VerityDataDevice => None, Self::VerityHashDevice => None, + + // The signature device does not impose any additional + // restrictions beyond its allowed partition types. + Self::VerityRootHashSignatureDevice => None, } } } @@ -430,6 +434,7 @@ impl SpecialReferenceKind { match self { Self::VerityDataDevice => Some(true), Self::VerityHashDevice => Some(true), + Self::VerityRootHashSignatureDevice => Some(true), } } } @@ -498,6 +503,13 @@ impl SpecialReferenceKind { PartitionType::UsrVerity, PartitionType::LinuxGeneric, ])), + + // There is no standard discoverable partition type GUID for a + // verity root hash signature partition, so only a generic Linux + // partition type is allowed. + Self::VerityRootHashSignatureDevice => { + Some(AllowBlockList::Allow(vec![PartitionType::LinuxGeneric])) + } } } } diff --git a/crates/trident_api/src/config/host/storage/verity.rs b/crates/trident_api/src/config/host/storage/verity.rs index 5819876c54..28e6632ae9 100644 --- a/crates/trident_api/src/config/host/storage/verity.rs +++ b/crates/trident_api/src/config/host/storage/verity.rs @@ -31,6 +31,17 @@ pub struct VerityDevice { #[cfg_attr(feature = "schemars", schemars(schema_with = "block_device_id_schema"))] pub hash_device_id: BlockDeviceId, + /// The ID of the partition holding the dm-verity root hash signature, if any. + /// + /// When set, Trident reads the PKCS#7/DER root hash signature directly + /// from this partition and uses it to open the verity device with + /// `veritysetup open --root-hash-signature=...`, enabling kernel-enforced + /// signature verification of the verity root hash. The certificate + /// matching the signature must exist in the kernel keyring. + #[serde(default, skip_serializing_if = "Option::is_none")] + #[cfg_attr(feature = "schemars", schemars(schema_with = "block_device_id_schema"))] + pub signature_device_id: Option, + // Specifies how a mismatch between the hash and the data partition is handled. #[serde(default)] pub corruption_option: VerityCorruptionOption, From 77252a46357fa2cc58604fe14bfc7c7596b72252 Mon Sep 17 00:00:00 2001 From: Brian Fjeldstad Date: Thu, 8 Oct 2026 15:57:57 +0000 Subject: [PATCH 2/8] hostconfig: fix compile sites for new VerityDevice field Adds signature_device_id: None to the remaining VerityDevice struct literals across the codebase (test fixtures, sample configs, engine and subsystem call sites) so the workspace builds cleanly with the new optional field. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- crates/trident/src/engine/context/mod.rs | 2 ++ crates/trident/src/engine/rollback.rs | 3 +++ crates/trident/src/engine/storage/verity.rs | 2 ++ crates/trident/src/init/acl/mod.rs | 1 + crates/trident/src/init/offline/mod.rs | 1 + crates/trident/src/osimage/cosi/derived_hc.rs | 1 + crates/trident/src/subsystems/selinux.rs | 1 + crates/trident/src/subsystems/storage/fstab.rs | 2 ++ crates/trident/src/subsystems/storage/osimage.rs | 3 +++ crates/trident_api/src/config/host/mod.rs | 3 +++ crates/trident_api/src/config/host/storage/mod.rs | 3 +++ .../src/config/host/storage/storage_graph/graph.rs | 5 +++++ .../config/host/storage/storage_graph/validation_tests.rs | 8 ++++++++ crates/trident_api/src/samples/sample_hc.rs | 2 ++ 14 files changed, 37 insertions(+) diff --git a/crates/trident/src/engine/context/mod.rs b/crates/trident/src/engine/context/mod.rs index 7481c55035..72cd3323a3 100644 --- a/crates/trident/src/engine/context/mod.rs +++ b/crates/trident/src/engine/context/mod.rs @@ -757,6 +757,7 @@ mod tests { name: "root".to_string(), data_device_id: "root-data".to_string(), hash_device_id: "root-hash".to_string(), + signature_device_id: None, ..Default::default() }]; @@ -767,6 +768,7 @@ mod tests { name: "root".to_string(), data_device_id: "root-data".to_string(), hash_device_id: "root-hash".to_string(), + signature_device_id: None, ..Default::default() } ); diff --git a/crates/trident/src/engine/rollback.rs b/crates/trident/src/engine/rollback.rs index e92795239b..1d21ebaf88 100644 --- a/crates/trident/src/engine/rollback.rs +++ b/crates/trident/src/engine/rollback.rs @@ -984,6 +984,7 @@ mod tests { name: "root".into(), data_device_id: "root-data".into(), hash_device_id: "root-hash".into(), + signature_device_id: None, ..Default::default() }]; @@ -1358,6 +1359,7 @@ mod functional_test { name: "root".to_string(), data_device_id: "root-data".to_string(), hash_device_id: "root-hash".to_string(), + signature_device_id: None, ..Default::default() }]; @@ -1414,6 +1416,7 @@ mod functional_test { name: "root".to_string(), data_device_id: "root-data".to_string(), hash_device_id: "root-hash".to_string(), + signature_device_id: None, ..Default::default() }]; diff --git a/crates/trident/src/engine/storage/verity.rs b/crates/trident/src/engine/storage/verity.rs index c6540e1b88..87ce34083a 100644 --- a/crates/trident/src/engine/storage/verity.rs +++ b/crates/trident/src/engine/storage/verity.rs @@ -640,6 +640,7 @@ mod functional_test { name: "root".into(), data_device_id: "root-data".into(), hash_device_id: "root-hash".into(), + signature_device_id: None, ..Default::default() }], filesystems: vec![ @@ -771,6 +772,7 @@ mod functional_test { name: "root".into(), data_device_id: "root".into(), hash_device_id: "root-hash".into(), + signature_device_id: None, ..Default::default() }], ..Default::default() diff --git a/crates/trident/src/init/acl/mod.rs b/crates/trident/src/init/acl/mod.rs index a33867319f..9b284f464e 100644 --- a/crates/trident/src/init/acl/mod.rs +++ b/crates/trident/src/init/acl/mod.rs @@ -278,6 +278,7 @@ fn inner_initial_host_status( name: "usr".to_string(), data_device_id: "usr-data".to_string(), hash_device_id: "usr-hash".to_string(), + signature_device_id: None, ..Default::default() }], ab_update: Some(AbUpdate { diff --git a/crates/trident/src/init/offline/mod.rs b/crates/trident/src/init/offline/mod.rs index d11e3288ad..c7bd44b5be 100644 --- a/crates/trident/src/init/offline/mod.rs +++ b/crates/trident/src/init/offline/mod.rs @@ -226,6 +226,7 @@ fn generate_host_status( name: prism_verity.name.clone(), data_device_id, hash_device_id, + signature_device_id: None, corruption_option: match prism_verity.corruption_option.as_deref() { None => VerityCorruptionOption::default(), Some("io-error") => VerityCorruptionOption::IoError, diff --git a/crates/trident/src/osimage/cosi/derived_hc.rs b/crates/trident/src/osimage/cosi/derived_hc.rs index 1c9a8671fd..9ab1b0e142 100644 --- a/crates/trident/src/osimage/cosi/derived_hc.rs +++ b/crates/trident/src/osimage/cosi/derived_hc.rs @@ -115,6 +115,7 @@ pub(super) fn derive_host_configuration_inner( name: verity_name, data_device_id: partition_id.clone(), hash_device_id: hash_partition_id.clone(), + signature_device_id: None, corruption_option: Default::default(), }); diff --git a/crates/trident/src/subsystems/selinux.rs b/crates/trident/src/subsystems/selinux.rs index fc59ace277..36093c8b0f 100644 --- a/crates/trident/src/subsystems/selinux.rs +++ b/crates/trident/src/subsystems/selinux.rs @@ -507,6 +507,7 @@ mod tests { name: "root".into(), data_device_id: "root-data".into(), hash_device_id: "root-hash".into(), + signature_device_id: None, corruption_option: VerityCorruptionOption::Ignore, }], ..Default::default() diff --git a/crates/trident/src/subsystems/storage/fstab.rs b/crates/trident/src/subsystems/storage/fstab.rs index c26333824e..92d01a5e9d 100644 --- a/crates/trident/src/subsystems/storage/fstab.rs +++ b/crates/trident/src/subsystems/storage/fstab.rs @@ -505,6 +505,7 @@ mod tests { name: "root".to_owned(), data_device_id: "root-data".to_owned(), hash_device_id: "root-hash".to_owned(), + signature_device_id: None, ..Default::default() }], filesystems: vec![ @@ -663,6 +664,7 @@ mod tests { name: "usr".to_owned(), data_device_id: "usr-data".to_owned(), hash_device_id: "usr-hash".to_owned(), + signature_device_id: None, ..Default::default() }], filesystems: vec![ diff --git a/crates/trident/src/subsystems/storage/osimage.rs b/crates/trident/src/subsystems/storage/osimage.rs index 387bb75cd4..8b39d98bdc 100644 --- a/crates/trident/src/subsystems/storage/osimage.rs +++ b/crates/trident/src/subsystems/storage/osimage.rs @@ -1105,6 +1105,7 @@ mod tests { name: "verity".into(), data_device_id: "data".into(), hash_device_id: "hash".into(), + signature_device_id: None, ..Default::default() }], filesystems: vec![FileSystem { @@ -1157,6 +1158,7 @@ mod tests { name: "verity".into(), data_device_id: "data".into(), hash_device_id: "hash".into(), + signature_device_id: None, ..Default::default() }], filesystems: vec![FileSystem { @@ -1401,6 +1403,7 @@ mod tests { name: "verity".into(), data_device_id: "data".into(), hash_device_id: "hash".into(), + signature_device_id: None, ..Default::default() }], filesystems: vec![FileSystem { diff --git a/crates/trident_api/src/config/host/mod.rs b/crates/trident_api/src/config/host/mod.rs index 6a362bff55..4c0d15eaa6 100644 --- a/crates/trident_api/src/config/host/mod.rs +++ b/crates/trident_api/src/config/host/mod.rs @@ -798,6 +798,7 @@ mod tests { id: "root".into(), data_device_id: "root-data".into(), hash_device_id: "root-hash".into(), + signature_device_id: None, name: "root".into(), ..Default::default() }], @@ -931,6 +932,7 @@ mod tests { name: "usr".to_string(), data_device_id: "usr-data".into(), hash_device_id: "usr-hash".into(), + signature_device_id: None, ..Default::default() }, VerityDevice { @@ -938,6 +940,7 @@ mod tests { name: "root".to_string(), data_device_id: "root-data".into(), hash_device_id: "root-hash".into(), + signature_device_id: None, ..Default::default() }, ], diff --git a/crates/trident_api/src/config/host/storage/mod.rs b/crates/trident_api/src/config/host/storage/mod.rs index 70f4e89b4c..1db1754367 100644 --- a/crates/trident_api/src/config/host/storage/mod.rs +++ b/crates/trident_api/src/config/host/storage/mod.rs @@ -761,6 +761,7 @@ mod tests { name: "root".into(), data_device_id: "root-a".into(), hash_device_id: "root-a-verity".into(), + signature_device_id: None, ..Default::default() }]; storage.filesystems.push(FileSystem { @@ -2760,6 +2761,7 @@ mod tests { name: "usr".into(), data_device_id: "some-data-device".into(), hash_device_id: "some-hash-device".into(), + signature_device_id: None, ..Default::default() }) .expect("Failed to validate usr verity device"); @@ -2772,6 +2774,7 @@ mod tests { name: "usr-foo".into(), data_device_id: "some-data-device".into(), hash_device_id: "some-hash-device".into(), + signature_device_id: None, ..Default::default() }) .unwrap_err(), diff --git a/crates/trident_api/src/config/host/storage/storage_graph/graph.rs b/crates/trident_api/src/config/host/storage/storage_graph/graph.rs index f09f06a4ed..d0f286296f 100644 --- a/crates/trident_api/src/config/host/storage/storage_graph/graph.rs +++ b/crates/trident_api/src/config/host/storage/storage_graph/graph.rs @@ -390,6 +390,7 @@ mod tests { name: "myVerityDevice".into(), data_device_id: "data".into(), hash_device_id: "hash".into(), + signature_device_id: None, ..Default::default() }; let backing_node_idx = graph.inner.add_node((&verity_dev).into()); @@ -420,6 +421,7 @@ mod tests { name: "myVerityDevice2".into(), data_device_id: "data2".into(), hash_device_id: "hash2".into(), + signature_device_id: None, ..Default::default() }; let backing_node_idx2 = graph.inner.add_node((&verity_dev2).into()); @@ -510,6 +512,7 @@ mod tests { name: "myVerityDevice".into(), data_device_id: "data".into(), hash_device_id: "hash".into(), + signature_device_id: None, ..Default::default() }), })); @@ -607,6 +610,7 @@ mod tests { name: "myVerityDevice".into(), data_device_id: "data".into(), hash_device_id: "hash".into(), + signature_device_id: None, ..Default::default() }), })); @@ -759,6 +763,7 @@ mod tests { name: "verity".into(), data_device_id: "data".into(), hash_device_id: "hash".into(), + signature_device_id: None, ..Default::default() }], encryption: Some(Encryption { diff --git a/crates/trident_api/src/config/host/storage/storage_graph/validation_tests.rs b/crates/trident_api/src/config/host/storage/storage_graph/validation_tests.rs index 1242e04ac0..5309317aff 100644 --- a/crates/trident_api/src/config/host/storage/storage_graph/validation_tests.rs +++ b/crates/trident_api/src/config/host/storage/storage_graph/validation_tests.rs @@ -902,6 +902,7 @@ mod verity { id: "verity_dev".into(), data_device_id: "part1".into(), hash_device_id: "part2".into(), + signature_device_id: None, name: "verity".into(), ..Default::default() }; @@ -953,6 +954,7 @@ mod verity { id: "verity_dev".into(), data_device_id: "raid".into(), hash_device_id: "part3".into(), + signature_device_id: None, name: "verity".into(), ..Default::default() }; @@ -993,6 +995,7 @@ mod verity { id: "verity_dev".into(), data_device_id: "part1".into(), hash_device_id: "part2".into(), + signature_device_id: None, name: "verity".into(), ..Default::default() }; @@ -1040,6 +1043,7 @@ mod verity { id: "verity_dev".into(), data_device_id: "part1".into(), hash_device_id: "part2".into(), + signature_device_id: None, name: "verity".into(), ..Default::default() }; @@ -1087,6 +1091,7 @@ mod verity { id: "verity1".into(), data_device_id: "part1".into(), hash_device_id: "part2".into(), + signature_device_id: None, name: "verity".into(), ..Default::default() }; @@ -1115,6 +1120,7 @@ mod verity { id: "verity2".into(), data_device_id: "part3".into(), hash_device_id: "part4".into(), + signature_device_id: None, name: "verity".into(), ..Default::default() }; @@ -1144,6 +1150,7 @@ mod verity { id: "verity".into(), data_device_id: "partition".into(), hash_device_id: "nonexistent-hash-partition".into(), + signature_device_id: None, name: "verity".into(), ..Default::default() }; @@ -1188,6 +1195,7 @@ mod verity { id: "verity_dev".into(), data_device_id: "part1".into(), hash_device_id: "part2".into(), + signature_device_id: None, name: "verity".into(), ..Default::default() }; diff --git a/crates/trident_api/src/samples/sample_hc.rs b/crates/trident_api/src/samples/sample_hc.rs index c77309b18c..8ff2c20cdb 100644 --- a/crates/trident_api/src/samples/sample_hc.rs +++ b/crates/trident_api/src/samples/sample_hc.rs @@ -595,6 +595,7 @@ pub fn sample_host_configuration(name: &str) -> Result<(&'static str, HostConfig id: "root".into(), data_device_id: "root-data".into(), hash_device_id: "root-hash".into(), + signature_device_id: None, name: "root".into(), ..Default::default() }], @@ -1069,6 +1070,7 @@ pub fn sample_host_configuration(name: &str) -> Result<(&'static str, HostConfig id: "root".into(), data_device_id: "root-data".into(), hash_device_id: "root-hash".into(), + signature_device_id: None, name: "root".into(), ..Default::default() }], From 3ba0bfed06a3fb54a8cb9f6802359d31db0edc88 Mon Sep 17 00:00:00 2001 From: Brian Fjeldstad Date: Thu, 8 Oct 2026 16:18:37 +0000 Subject: [PATCH 3/8] hostconfig: rename verity signature device identifiers Renames for clarity ahead of further stack PRs: - SpecialReferenceKind::VerityRootHashSignatureDevice -> VerityHashSignatureDevice - VerityDevice.signature_device_id -> hash_signature_device_id Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- crates/trident/src/engine/context/mod.rs | 4 ++-- crates/trident/src/engine/rollback.rs | 6 +++--- crates/trident/src/engine/storage/verity.rs | 4 ++-- crates/trident/src/init/acl/mod.rs | 2 +- crates/trident/src/init/offline/mod.rs | 2 +- crates/trident/src/osimage/cosi/derived_hc.rs | 2 +- crates/trident/src/subsystems/selinux.rs | 2 +- crates/trident/src/subsystems/storage/fstab.rs | 4 ++-- crates/trident/src/subsystems/storage/osimage.rs | 6 +++--- crates/trident_api/src/config/host/mod.rs | 6 +++--- .../trident_api/src/config/host/storage/mod.rs | 6 +++--- .../storage/storage_graph/builder/partition.rs | 2 +- .../config/host/storage/storage_graph/display.rs | 2 +- .../config/host/storage/storage_graph/graph.rs | 10 +++++----- .../config/host/storage/storage_graph/node.rs | 6 +++--- .../host/storage/storage_graph/references.rs | 2 +- .../host/storage/storage_graph/rules/mod.rs | 6 +++--- .../storage/storage_graph/validation_tests.rs | 16 ++++++++-------- .../src/config/host/storage/verity.rs | 2 +- crates/trident_api/src/samples/sample_hc.rs | 4 ++-- 20 files changed, 47 insertions(+), 47 deletions(-) diff --git a/crates/trident/src/engine/context/mod.rs b/crates/trident/src/engine/context/mod.rs index 72cd3323a3..db308b99c0 100644 --- a/crates/trident/src/engine/context/mod.rs +++ b/crates/trident/src/engine/context/mod.rs @@ -757,7 +757,7 @@ mod tests { name: "root".to_string(), data_device_id: "root-data".to_string(), hash_device_id: "root-hash".to_string(), - signature_device_id: None, + hash_signature_device_id: None, ..Default::default() }]; @@ -768,7 +768,7 @@ mod tests { name: "root".to_string(), data_device_id: "root-data".to_string(), hash_device_id: "root-hash".to_string(), - signature_device_id: None, + hash_signature_device_id: None, ..Default::default() } ); diff --git a/crates/trident/src/engine/rollback.rs b/crates/trident/src/engine/rollback.rs index 1d21ebaf88..f7fb077157 100644 --- a/crates/trident/src/engine/rollback.rs +++ b/crates/trident/src/engine/rollback.rs @@ -984,7 +984,7 @@ mod tests { name: "root".into(), data_device_id: "root-data".into(), hash_device_id: "root-hash".into(), - signature_device_id: None, + hash_signature_device_id: None, ..Default::default() }]; @@ -1359,7 +1359,7 @@ mod functional_test { name: "root".to_string(), data_device_id: "root-data".to_string(), hash_device_id: "root-hash".to_string(), - signature_device_id: None, + hash_signature_device_id: None, ..Default::default() }]; @@ -1416,7 +1416,7 @@ mod functional_test { name: "root".to_string(), data_device_id: "root-data".to_string(), hash_device_id: "root-hash".to_string(), - signature_device_id: None, + hash_signature_device_id: None, ..Default::default() }]; diff --git a/crates/trident/src/engine/storage/verity.rs b/crates/trident/src/engine/storage/verity.rs index 87ce34083a..9b4c613ffb 100644 --- a/crates/trident/src/engine/storage/verity.rs +++ b/crates/trident/src/engine/storage/verity.rs @@ -640,7 +640,7 @@ mod functional_test { name: "root".into(), data_device_id: "root-data".into(), hash_device_id: "root-hash".into(), - signature_device_id: None, + hash_signature_device_id: None, ..Default::default() }], filesystems: vec![ @@ -772,7 +772,7 @@ mod functional_test { name: "root".into(), data_device_id: "root".into(), hash_device_id: "root-hash".into(), - signature_device_id: None, + hash_signature_device_id: None, ..Default::default() }], ..Default::default() diff --git a/crates/trident/src/init/acl/mod.rs b/crates/trident/src/init/acl/mod.rs index 9b284f464e..0f565800ed 100644 --- a/crates/trident/src/init/acl/mod.rs +++ b/crates/trident/src/init/acl/mod.rs @@ -278,7 +278,7 @@ fn inner_initial_host_status( name: "usr".to_string(), data_device_id: "usr-data".to_string(), hash_device_id: "usr-hash".to_string(), - signature_device_id: None, + hash_signature_device_id: None, ..Default::default() }], ab_update: Some(AbUpdate { diff --git a/crates/trident/src/init/offline/mod.rs b/crates/trident/src/init/offline/mod.rs index c7bd44b5be..23c1316534 100644 --- a/crates/trident/src/init/offline/mod.rs +++ b/crates/trident/src/init/offline/mod.rs @@ -226,7 +226,7 @@ fn generate_host_status( name: prism_verity.name.clone(), data_device_id, hash_device_id, - signature_device_id: None, + hash_signature_device_id: None, corruption_option: match prism_verity.corruption_option.as_deref() { None => VerityCorruptionOption::default(), Some("io-error") => VerityCorruptionOption::IoError, diff --git a/crates/trident/src/osimage/cosi/derived_hc.rs b/crates/trident/src/osimage/cosi/derived_hc.rs index 9ab1b0e142..622d62bb9e 100644 --- a/crates/trident/src/osimage/cosi/derived_hc.rs +++ b/crates/trident/src/osimage/cosi/derived_hc.rs @@ -115,7 +115,7 @@ pub(super) fn derive_host_configuration_inner( name: verity_name, data_device_id: partition_id.clone(), hash_device_id: hash_partition_id.clone(), - signature_device_id: None, + hash_signature_device_id: None, corruption_option: Default::default(), }); diff --git a/crates/trident/src/subsystems/selinux.rs b/crates/trident/src/subsystems/selinux.rs index 36093c8b0f..f7149d2ce7 100644 --- a/crates/trident/src/subsystems/selinux.rs +++ b/crates/trident/src/subsystems/selinux.rs @@ -507,7 +507,7 @@ mod tests { name: "root".into(), data_device_id: "root-data".into(), hash_device_id: "root-hash".into(), - signature_device_id: None, + hash_signature_device_id: None, corruption_option: VerityCorruptionOption::Ignore, }], ..Default::default() diff --git a/crates/trident/src/subsystems/storage/fstab.rs b/crates/trident/src/subsystems/storage/fstab.rs index 92d01a5e9d..b9b6cc635c 100644 --- a/crates/trident/src/subsystems/storage/fstab.rs +++ b/crates/trident/src/subsystems/storage/fstab.rs @@ -505,7 +505,7 @@ mod tests { name: "root".to_owned(), data_device_id: "root-data".to_owned(), hash_device_id: "root-hash".to_owned(), - signature_device_id: None, + hash_signature_device_id: None, ..Default::default() }], filesystems: vec![ @@ -664,7 +664,7 @@ mod tests { name: "usr".to_owned(), data_device_id: "usr-data".to_owned(), hash_device_id: "usr-hash".to_owned(), - signature_device_id: None, + hash_signature_device_id: None, ..Default::default() }], filesystems: vec![ diff --git a/crates/trident/src/subsystems/storage/osimage.rs b/crates/trident/src/subsystems/storage/osimage.rs index 8b39d98bdc..4e393f2c11 100644 --- a/crates/trident/src/subsystems/storage/osimage.rs +++ b/crates/trident/src/subsystems/storage/osimage.rs @@ -1105,7 +1105,7 @@ mod tests { name: "verity".into(), data_device_id: "data".into(), hash_device_id: "hash".into(), - signature_device_id: None, + hash_signature_device_id: None, ..Default::default() }], filesystems: vec![FileSystem { @@ -1158,7 +1158,7 @@ mod tests { name: "verity".into(), data_device_id: "data".into(), hash_device_id: "hash".into(), - signature_device_id: None, + hash_signature_device_id: None, ..Default::default() }], filesystems: vec![FileSystem { @@ -1403,7 +1403,7 @@ mod tests { name: "verity".into(), data_device_id: "data".into(), hash_device_id: "hash".into(), - signature_device_id: None, + hash_signature_device_id: None, ..Default::default() }], filesystems: vec![FileSystem { diff --git a/crates/trident_api/src/config/host/mod.rs b/crates/trident_api/src/config/host/mod.rs index 4c0d15eaa6..1610225dce 100644 --- a/crates/trident_api/src/config/host/mod.rs +++ b/crates/trident_api/src/config/host/mod.rs @@ -798,7 +798,7 @@ mod tests { id: "root".into(), data_device_id: "root-data".into(), hash_device_id: "root-hash".into(), - signature_device_id: None, + hash_signature_device_id: None, name: "root".into(), ..Default::default() }], @@ -932,7 +932,7 @@ mod tests { name: "usr".to_string(), data_device_id: "usr-data".into(), hash_device_id: "usr-hash".into(), - signature_device_id: None, + hash_signature_device_id: None, ..Default::default() }, VerityDevice { @@ -940,7 +940,7 @@ mod tests { name: "root".to_string(), data_device_id: "root-data".into(), hash_device_id: "root-hash".into(), - signature_device_id: None, + hash_signature_device_id: None, ..Default::default() }, ], diff --git a/crates/trident_api/src/config/host/storage/mod.rs b/crates/trident_api/src/config/host/storage/mod.rs index 1db1754367..28fbb19cad 100644 --- a/crates/trident_api/src/config/host/storage/mod.rs +++ b/crates/trident_api/src/config/host/storage/mod.rs @@ -761,7 +761,7 @@ mod tests { name: "root".into(), data_device_id: "root-a".into(), hash_device_id: "root-a-verity".into(), - signature_device_id: None, + hash_signature_device_id: None, ..Default::default() }]; storage.filesystems.push(FileSystem { @@ -2761,7 +2761,7 @@ mod tests { name: "usr".into(), data_device_id: "some-data-device".into(), hash_device_id: "some-hash-device".into(), - signature_device_id: None, + hash_signature_device_id: None, ..Default::default() }) .expect("Failed to validate usr verity device"); @@ -2774,7 +2774,7 @@ mod tests { name: "usr-foo".into(), data_device_id: "some-data-device".into(), hash_device_id: "some-hash-device".into(), - signature_device_id: None, + hash_signature_device_id: None, ..Default::default() }) .unwrap_err(), diff --git a/crates/trident_api/src/config/host/storage/storage_graph/builder/partition.rs b/crates/trident_api/src/config/host/storage/storage_graph/builder/partition.rs index efd2d5a5ac..da3db9fa3f 100644 --- a/crates/trident_api/src/config/host/storage/storage_graph/builder/partition.rs +++ b/crates/trident_api/src/config/host/storage/storage_graph/builder/partition.rs @@ -39,7 +39,7 @@ impl SpecialReferenceKind { // The verity root hash signature device should NOT pass through // partition attributes either, as it is entirely consumed by the // verity device. - SpecialReferenceKind::VerityRootHashSignatureDevice => false, + SpecialReferenceKind::VerityHashSignatureDevice => false, } } } diff --git a/crates/trident_api/src/config/host/storage/storage_graph/display.rs b/crates/trident_api/src/config/host/storage/storage_graph/display.rs index 44a937fc62..1681dd001a 100644 --- a/crates/trident_api/src/config/host/storage/storage_graph/display.rs +++ b/crates/trident_api/src/config/host/storage/storage_graph/display.rs @@ -57,7 +57,7 @@ impl Display for SpecialReferenceKind { match self { Self::VerityDataDevice => write!(f, "verity-data-device"), Self::VerityHashDevice => write!(f, "verity-hash-device"), - Self::VerityRootHashSignatureDevice => write!(f, "verity-root-hash-signature-device"), + Self::VerityHashSignatureDevice => write!(f, "verity-hash-signature-device"), } } } diff --git a/crates/trident_api/src/config/host/storage/storage_graph/graph.rs b/crates/trident_api/src/config/host/storage/storage_graph/graph.rs index d0f286296f..31abc2c02a 100644 --- a/crates/trident_api/src/config/host/storage/storage_graph/graph.rs +++ b/crates/trident_api/src/config/host/storage/storage_graph/graph.rs @@ -390,7 +390,7 @@ mod tests { name: "myVerityDevice".into(), data_device_id: "data".into(), hash_device_id: "hash".into(), - signature_device_id: None, + hash_signature_device_id: None, ..Default::default() }; let backing_node_idx = graph.inner.add_node((&verity_dev).into()); @@ -421,7 +421,7 @@ mod tests { name: "myVerityDevice2".into(), data_device_id: "data2".into(), hash_device_id: "hash2".into(), - signature_device_id: None, + hash_signature_device_id: None, ..Default::default() }; let backing_node_idx2 = graph.inner.add_node((&verity_dev2).into()); @@ -512,7 +512,7 @@ mod tests { name: "myVerityDevice".into(), data_device_id: "data".into(), hash_device_id: "hash".into(), - signature_device_id: None, + hash_signature_device_id: None, ..Default::default() }), })); @@ -610,7 +610,7 @@ mod tests { name: "myVerityDevice".into(), data_device_id: "data".into(), hash_device_id: "hash".into(), - signature_device_id: None, + hash_signature_device_id: None, ..Default::default() }), })); @@ -763,7 +763,7 @@ mod tests { name: "verity".into(), data_device_id: "data".into(), hash_device_id: "hash".into(), - signature_device_id: None, + hash_signature_device_id: None, ..Default::default() }], encryption: Some(Encryption { diff --git a/crates/trident_api/src/config/host/storage/storage_graph/node.rs b/crates/trident_api/src/config/host/storage/storage_graph/node.rs index 5677f048cf..578a25b759 100644 --- a/crates/trident_api/src/config/host/storage/storage_graph/node.rs +++ b/crates/trident_api/src/config/host/storage/storage_graph/node.rs @@ -155,10 +155,10 @@ impl StorageGraphNode { ), ]; - if let Some(signature_device_id) = &verity_device.signature_device_id { + if let Some(hash_signature_device_id) = &verity_device.hash_signature_device_id { refs.push(StorageReference::new_special( - SpecialReferenceKind::VerityRootHashSignatureDevice, - signature_device_id, + SpecialReferenceKind::VerityHashSignatureDevice, + hash_signature_device_id, )); } diff --git a/crates/trident_api/src/config/host/storage/storage_graph/references.rs b/crates/trident_api/src/config/host/storage/storage_graph/references.rs index 98d49c8411..630f6b20bd 100644 --- a/crates/trident_api/src/config/host/storage/storage_graph/references.rs +++ b/crates/trident_api/src/config/host/storage/storage_graph/references.rs @@ -31,7 +31,7 @@ pub enum SpecialReferenceKind { VerityHashDevice, /// A reference to a Verity device's root hash signature device. - VerityRootHashSignatureDevice, + VerityHashSignatureDevice, } /// A reference to a block device in the configuration. diff --git a/crates/trident_api/src/config/host/storage/storage_graph/rules/mod.rs b/crates/trident_api/src/config/host/storage/storage_graph/rules/mod.rs index 12facab027..f9fec356fd 100644 --- a/crates/trident_api/src/config/host/storage/storage_graph/rules/mod.rs +++ b/crates/trident_api/src/config/host/storage/storage_graph/rules/mod.rs @@ -220,7 +220,7 @@ impl SpecialReferenceKind { // The signature device does not impose any additional // restrictions beyond its allowed partition types. - Self::VerityRootHashSignatureDevice => None, + Self::VerityHashSignatureDevice => None, } } } @@ -434,7 +434,7 @@ impl SpecialReferenceKind { match self { Self::VerityDataDevice => Some(true), Self::VerityHashDevice => Some(true), - Self::VerityRootHashSignatureDevice => Some(true), + Self::VerityHashSignatureDevice => Some(true), } } } @@ -507,7 +507,7 @@ impl SpecialReferenceKind { // There is no standard discoverable partition type GUID for a // verity root hash signature partition, so only a generic Linux // partition type is allowed. - Self::VerityRootHashSignatureDevice => { + Self::VerityHashSignatureDevice => { Some(AllowBlockList::Allow(vec![PartitionType::LinuxGeneric])) } } diff --git a/crates/trident_api/src/config/host/storage/storage_graph/validation_tests.rs b/crates/trident_api/src/config/host/storage/storage_graph/validation_tests.rs index 5309317aff..88378a0f24 100644 --- a/crates/trident_api/src/config/host/storage/storage_graph/validation_tests.rs +++ b/crates/trident_api/src/config/host/storage/storage_graph/validation_tests.rs @@ -902,7 +902,7 @@ mod verity { id: "verity_dev".into(), data_device_id: "part1".into(), hash_device_id: "part2".into(), - signature_device_id: None, + hash_signature_device_id: None, name: "verity".into(), ..Default::default() }; @@ -954,7 +954,7 @@ mod verity { id: "verity_dev".into(), data_device_id: "raid".into(), hash_device_id: "part3".into(), - signature_device_id: None, + hash_signature_device_id: None, name: "verity".into(), ..Default::default() }; @@ -995,7 +995,7 @@ mod verity { id: "verity_dev".into(), data_device_id: "part1".into(), hash_device_id: "part2".into(), - signature_device_id: None, + hash_signature_device_id: None, name: "verity".into(), ..Default::default() }; @@ -1043,7 +1043,7 @@ mod verity { id: "verity_dev".into(), data_device_id: "part1".into(), hash_device_id: "part2".into(), - signature_device_id: None, + hash_signature_device_id: None, name: "verity".into(), ..Default::default() }; @@ -1091,7 +1091,7 @@ mod verity { id: "verity1".into(), data_device_id: "part1".into(), hash_device_id: "part2".into(), - signature_device_id: None, + hash_signature_device_id: None, name: "verity".into(), ..Default::default() }; @@ -1120,7 +1120,7 @@ mod verity { id: "verity2".into(), data_device_id: "part3".into(), hash_device_id: "part4".into(), - signature_device_id: None, + hash_signature_device_id: None, name: "verity".into(), ..Default::default() }; @@ -1150,7 +1150,7 @@ mod verity { id: "verity".into(), data_device_id: "partition".into(), hash_device_id: "nonexistent-hash-partition".into(), - signature_device_id: None, + hash_signature_device_id: None, name: "verity".into(), ..Default::default() }; @@ -1195,7 +1195,7 @@ mod verity { id: "verity_dev".into(), data_device_id: "part1".into(), hash_device_id: "part2".into(), - signature_device_id: None, + hash_signature_device_id: None, name: "verity".into(), ..Default::default() }; diff --git a/crates/trident_api/src/config/host/storage/verity.rs b/crates/trident_api/src/config/host/storage/verity.rs index 28e6632ae9..e1be56bf9e 100644 --- a/crates/trident_api/src/config/host/storage/verity.rs +++ b/crates/trident_api/src/config/host/storage/verity.rs @@ -40,7 +40,7 @@ pub struct VerityDevice { /// matching the signature must exist in the kernel keyring. #[serde(default, skip_serializing_if = "Option::is_none")] #[cfg_attr(feature = "schemars", schemars(schema_with = "block_device_id_schema"))] - pub signature_device_id: Option, + pub hash_signature_device_id: Option, // Specifies how a mismatch between the hash and the data partition is handled. #[serde(default)] diff --git a/crates/trident_api/src/samples/sample_hc.rs b/crates/trident_api/src/samples/sample_hc.rs index 8ff2c20cdb..ff9f9f8f4a 100644 --- a/crates/trident_api/src/samples/sample_hc.rs +++ b/crates/trident_api/src/samples/sample_hc.rs @@ -595,7 +595,7 @@ pub fn sample_host_configuration(name: &str) -> Result<(&'static str, HostConfig id: "root".into(), data_device_id: "root-data".into(), hash_device_id: "root-hash".into(), - signature_device_id: None, + hash_signature_device_id: None, name: "root".into(), ..Default::default() }], @@ -1070,7 +1070,7 @@ pub fn sample_host_configuration(name: &str) -> Result<(&'static str, HostConfig id: "root".into(), data_device_id: "root-data".into(), hash_device_id: "root-hash".into(), - signature_device_id: None, + hash_signature_device_id: None, name: "root".into(), ..Default::default() }], From b814b1c846f1f1984f1ff1fedc9e42ecc80dbe7b Mon Sep 17 00:00:00 2001 From: Brian Fjeldstad Date: Thu, 8 Oct 2026 16:34:17 +0000 Subject: [PATCH 4/8] hostconfig: defer signature device graph wiring to engine PR Move the construction of the VerityHashSignatureDevice special reference out of node.rs, since the graph-wiring logic is only meaningful once the engine can act on it. This will land in the engine PR instead. Mark the enum variant #[allow(dead_code)] in the meantime, consistent with the existing KnownMetadataVersion precedent. --- .../src/config/host/storage/storage_graph/node.rs | 13 ++----------- .../config/host/storage/storage_graph/references.rs | 1 + 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/crates/trident_api/src/config/host/storage/storage_graph/node.rs b/crates/trident_api/src/config/host/storage/storage_graph/node.rs index 578a25b759..2c87cca640 100644 --- a/crates/trident_api/src/config/host/storage/storage_graph/node.rs +++ b/crates/trident_api/src/config/host/storage/storage_graph/node.rs @@ -144,7 +144,7 @@ impl StorageGraphNode { vec![StorageReference::new_regular(&encrypted_volume.device_id)] } HostConfigBlockDevice::VerityDevice(verity_device) => { - let mut refs = vec![ + vec![ StorageReference::new_special( SpecialReferenceKind::VerityDataDevice, &verity_device.data_device_id, @@ -153,16 +153,7 @@ impl StorageGraphNode { SpecialReferenceKind::VerityHashDevice, &verity_device.hash_device_id, ), - ]; - - if let Some(hash_signature_device_id) = &verity_device.hash_signature_device_id { - refs.push(StorageReference::new_special( - SpecialReferenceKind::VerityHashSignatureDevice, - hash_signature_device_id, - )); - } - - refs + ] } }, Self::FileSystem(fs) => fs diff --git a/crates/trident_api/src/config/host/storage/storage_graph/references.rs b/crates/trident_api/src/config/host/storage/storage_graph/references.rs index 630f6b20bd..83260e41e2 100644 --- a/crates/trident_api/src/config/host/storage/storage_graph/references.rs +++ b/crates/trident_api/src/config/host/storage/storage_graph/references.rs @@ -31,6 +31,7 @@ pub enum SpecialReferenceKind { VerityHashDevice, /// A reference to a Verity device's root hash signature device. + #[allow(dead_code)] VerityHashSignatureDevice, } From 5fc2d8cfb20a06ed034d856aa0d3430866aecb3a Mon Sep 17 00:00:00 2001 From: Brian Fjeldstad Date: Thu, 8 Oct 2026 16:51:36 +0000 Subject: [PATCH 5/8] hostconfig: add serde round-trip tests for hash_signature_device_id Cover the Some(...) case, not just the None default: verify the field serializes/deserializes correctly under its camelCase name and round-trips through VerityDevice. Graph-level validation of the signature device is exercised separately once the reference is wired up in the engine PR. --- .../src/config/host/storage/verity.rs | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/crates/trident_api/src/config/host/storage/verity.rs b/crates/trident_api/src/config/host/storage/verity.rs index e1be56bf9e..bf49155369 100644 --- a/crates/trident_api/src/config/host/storage/verity.rs +++ b/crates/trident_api/src/config/host/storage/verity.rs @@ -88,3 +88,64 @@ impl VerityDevice { Path::new(DEV_MAPPER_PATH).join(format!("{}_new", self.name)) } } + +#[cfg(test)] +mod tests { + use super::*; + + fn base_verity_device() -> VerityDevice { + VerityDevice { + id: "verity".into(), + name: "root".into(), + data_device_id: "data".into(), + hash_device_id: "hash".into(), + hash_signature_device_id: None, + corruption_option: VerityCorruptionOption::default(), + } + } + + #[test] + fn test_verity_device_serde_roundtrip_without_signature() { + let device = base_verity_device(); + + let serialized = serde_json::to_string(&device).unwrap(); + assert!(!serialized.contains("hashSignatureDeviceId")); + + let deserialized: VerityDevice = serde_json::from_str(&serialized).unwrap(); + assert_eq!(deserialized, device); + assert_eq!(deserialized.hash_signature_device_id, None); + } + + #[test] + fn test_verity_device_serde_roundtrip_with_signature() { + let mut device = base_verity_device(); + device.hash_signature_device_id = Some("hash-signature".into()); + + let serialized = serde_json::to_string(&device).unwrap(); + assert!(serialized.contains("\"hashSignatureDeviceId\":\"hash-signature\"")); + + let deserialized: VerityDevice = serde_json::from_str(&serialized).unwrap(); + assert_eq!(deserialized, device); + assert_eq!( + deserialized.hash_signature_device_id, + Some("hash-signature".into()) + ); + } + + #[test] + fn test_verity_device_deserialize_signature_from_json() { + let json = serde_json::json!({ + "id": "verity", + "name": "root", + "dataDeviceId": "data", + "hashDeviceId": "hash", + "hashSignatureDeviceId": "hash-signature", + }); + + let device: VerityDevice = serde_json::from_value(json).unwrap(); + assert_eq!( + device.hash_signature_device_id, + Some("hash-signature".into()) + ); + } +} From a7c1f841a039b9c0a2c6eee34377d56ffea7f10f Mon Sep 17 00:00:00 2001 From: Brian Fjeldstad Date: Thu, 8 Oct 2026 16:53:31 +0000 Subject: [PATCH 6/8] docs: regenerate API schema/docs for hash_signature_device_id --- crates/trident_api/schemas/host-config-schema.json | 5 +++++ .../Host-Configuration/API-Reference/VerityDevice.md | 11 +++++++++++ 2 files changed, 16 insertions(+) diff --git a/crates/trident_api/schemas/host-config-schema.json b/crates/trident_api/schemas/host-config-schema.json index b95738c9df..9edeee1bbd 100644 --- a/crates/trident_api/schemas/host-config-schema.json +++ b/crates/trident_api/schemas/host-config-schema.json @@ -1817,6 +1817,11 @@ "type": "string", "format": "Block Device ID" }, + "hashSignatureDeviceId": { + "description": "The ID of the partition holding the dm-verity root hash signature, if any.\n\nWhen set, Trident reads the PKCS#7/DER root hash signature directly from this partition and uses it to open the verity device with `veritysetup open --root-hash-signature=...`, enabling kernel-enforced signature verification of the verity root hash. The certificate matching the signature must exist in the kernel keyring.", + "type": "string", + "format": "Block Device ID" + }, "id": { "description": "Block device id of the verity device.", "type": "string" diff --git a/docs/Reference/Host-Configuration/API-Reference/VerityDevice.md b/docs/Reference/Host-Configuration/API-Reference/VerityDevice.md index 6d4f2c69b1..19b89872bb 100644 --- a/docs/Reference/Host-Configuration/API-Reference/VerityDevice.md +++ b/docs/Reference/Host-Configuration/API-Reference/VerityDevice.md @@ -58,3 +58,14 @@ The value must be "root" for root partition "/". | Default | `"io-error"` | | Link | [VerityCorruptionOption](./VerityCorruptionOption.md) | +### `hashSignatureDeviceId` (optional) + +The ID of the partition holding the dm-verity root hash signature, if any. + +When set, Trident reads the PKCS#7/DER root hash signature directly from this partition and uses it to open the verity device with `veritysetup open --root-hash-signature=...`, enabling kernel-enforced signature verification of the verity root hash. The certificate matching the signature must exist in the kernel keyring. + +| Characteristic | Value | +| -------------- | ----------------- | +| Type | `string` | +| Format | `Block Device ID` | + From 9fd2c0b4f76828c8529cbd03b4e1747bd1e20b9e Mon Sep 17 00:00:00 2001 From: Brian Fjeldstad Date: Thu, 8 Oct 2026 17:06:28 +0000 Subject: [PATCH 7/8] hostconfig: simplify hash_signature_device_id doc comment Regenerate API schema/docs after simplifying the field description. --- crates/trident_api/schemas/host-config-schema.json | 2 +- crates/trident_api/src/config/host/storage/verity.rs | 8 +------- .../Host-Configuration/API-Reference/VerityDevice.md | 4 +--- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/crates/trident_api/schemas/host-config-schema.json b/crates/trident_api/schemas/host-config-schema.json index 9edeee1bbd..557c08f62b 100644 --- a/crates/trident_api/schemas/host-config-schema.json +++ b/crates/trident_api/schemas/host-config-schema.json @@ -1818,7 +1818,7 @@ "format": "Block Device ID" }, "hashSignatureDeviceId": { - "description": "The ID of the partition holding the dm-verity root hash signature, if any.\n\nWhen set, Trident reads the PKCS#7/DER root hash signature directly from this partition and uses it to open the verity device with `veritysetup open --root-hash-signature=...`, enabling kernel-enforced signature verification of the verity root hash. The certificate matching the signature must exist in the kernel keyring.", + "description": "The ID of the partition to use as the verity hash signature partition.", "type": "string", "format": "Block Device ID" }, diff --git a/crates/trident_api/src/config/host/storage/verity.rs b/crates/trident_api/src/config/host/storage/verity.rs index bf49155369..cbbae56dc6 100644 --- a/crates/trident_api/src/config/host/storage/verity.rs +++ b/crates/trident_api/src/config/host/storage/verity.rs @@ -31,13 +31,7 @@ pub struct VerityDevice { #[cfg_attr(feature = "schemars", schemars(schema_with = "block_device_id_schema"))] pub hash_device_id: BlockDeviceId, - /// The ID of the partition holding the dm-verity root hash signature, if any. - /// - /// When set, Trident reads the PKCS#7/DER root hash signature directly - /// from this partition and uses it to open the verity device with - /// `veritysetup open --root-hash-signature=...`, enabling kernel-enforced - /// signature verification of the verity root hash. The certificate - /// matching the signature must exist in the kernel keyring. + /// The ID of the partition to use as the verity hash signature partition. #[serde(default, skip_serializing_if = "Option::is_none")] #[cfg_attr(feature = "schemars", schemars(schema_with = "block_device_id_schema"))] pub hash_signature_device_id: Option, diff --git a/docs/Reference/Host-Configuration/API-Reference/VerityDevice.md b/docs/Reference/Host-Configuration/API-Reference/VerityDevice.md index 19b89872bb..799f67556f 100644 --- a/docs/Reference/Host-Configuration/API-Reference/VerityDevice.md +++ b/docs/Reference/Host-Configuration/API-Reference/VerityDevice.md @@ -60,9 +60,7 @@ The value must be "root" for root partition "/". ### `hashSignatureDeviceId` (optional) -The ID of the partition holding the dm-verity root hash signature, if any. - -When set, Trident reads the PKCS#7/DER root hash signature directly from this partition and uses it to open the verity device with `veritysetup open --root-hash-signature=...`, enabling kernel-enforced signature verification of the verity root hash. The certificate matching the signature must exist in the kernel keyring. +The ID of the partition to use as the verity hash signature partition. | Characteristic | Value | | -------------- | ----------------- | From 2ad831ab28cdc7a9506babfad3d29af5ae255f3c Mon Sep 17 00:00:00 2001 From: Brian Fjeldstad Date: Sat, 10 Oct 2026 16:47:44 +0000 Subject: [PATCH 8/8] fix: align verity signature partition types with hash policy Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: d61c42e7-3c43-4fe5-8c89-89d38ff9528b --- .../schemas/host-config-schema.json | 8 +++ .../src/config/host/storage/partitions.rs | 34 +++++++++--- .../host/storage/storage_graph/rules/mod.rs | 45 +++++++++++++-- .../API-Reference/PartitionType.md | 9 +++ .../Host-Configuration/Storage-Rules.md | 55 ++++++++++--------- 5 files changed, 109 insertions(+), 42 deletions(-) diff --git a/crates/trident_api/schemas/host-config-schema.json b/crates/trident_api/schemas/host-config-schema.json index 557c08f62b..babd0ebcdb 100644 --- a/crates/trident_api/schemas/host-config-schema.json +++ b/crates/trident_api/schemas/host-config-schema.json @@ -895,6 +895,14 @@ "root-verity" ] }, + { + "title": "Root verity hash signature partition", + "description": "x64: `41092b05-9fc8-4523-994f-2def0408b176`", + "type": "string", + "enum": [ + "root-verity-sig" + ] + }, { "title": "Home partition", "description": "`933ac7e1-2eb4-4f13-b844-0e14e2aef915`", diff --git a/crates/trident_api/src/config/host/storage/partitions.rs b/crates/trident_api/src/config/host/storage/partitions.rs index 5f020237d9..9791a68f7a 100644 --- a/crates/trident_api/src/config/host/storage/partitions.rs +++ b/crates/trident_api/src/config/host/storage/partitions.rs @@ -123,6 +123,11 @@ pub enum PartitionType { /// x64: `2c7357ed-ebd2-46d9-aec1-23d437ec2bf5` RootVerity, + /// # Root verity hash signature partition + /// + /// x64: `41092b05-9fc8-4523-994f-2def0408b176` + RootVeritySig, + /// # Home partition /// /// `933ac7e1-2eb4-4f13-b844-0e14e2aef915` @@ -201,6 +206,7 @@ impl PartitionType { PartitionType::Root => "root", PartitionType::Swap => "swap", PartitionType::RootVerity => "root-verity", + PartitionType::RootVeritySig => "root-verity-sig", PartitionType::Home => "home", PartitionType::Var => "var", PartitionType::Usr => "usr", @@ -232,6 +238,7 @@ impl PartitionType { Self::LinuxGeneric => Some(Self::LinuxGeneric), Self::RootVerity + | Self::RootVeritySig | Self::UsrVerity | Self::UsrVeritySig | Self::Esp @@ -259,6 +266,7 @@ impl From for DiscoverablePartitionType { PartitionType::Root => Self::Root, PartitionType::Swap => Self::Swap, PartitionType::RootVerity => Self::RootVerity, + PartitionType::RootVeritySig => Self::RootVeritySig, PartitionType::Home => Self::Home, PartitionType::Var => Self::Var, PartitionType::Usr => Self::Usr, @@ -328,11 +336,10 @@ impl From for PartitionType { | DiscoverablePartitionType::UsrAmd64VeritySig | DiscoverablePartitionType::UsrArm64VeritySig => Self::UsrVeritySig, - // Root verity signature partitions do not have a corresponding - // PartitionType variant yet, so we treat them as unknown. + // We coalesce all root verity signature variants into one. DiscoverablePartitionType::RootVeritySig | DiscoverablePartitionType::RootAmd64VeritySig - | DiscoverablePartitionType::RootArm64VeritySig => Self::Unknown(dpt.to_uuid()), + | DiscoverablePartitionType::RootArm64VeritySig => Self::RootVeritySig, // Fallback for unknown types DiscoverablePartitionType::Unknown(uuid) => Self::Unknown(uuid), @@ -419,17 +426,26 @@ mod tests { assert_eq!(PartitionType::from(dpt), PartitionType::UsrVeritySig); } - // Root-verity-sig variants have no corresponding PartitionType - // variant yet, so they still fall back to Unknown. + assert_eq!( + DiscoverablePartitionType::from(PartitionType::RootVeritySig), + DiscoverablePartitionType::RootVeritySig + ); + assert_eq!( + PartitionType::RootVeritySig.to_sdrepart_part_type(), + "root-verity-sig" + ); + let root_sig: PartitionType = serde_yaml::from_str("root-verity-sig").unwrap(); + assert_eq!(root_sig, PartitionType::RootVeritySig); + assert_eq!( + serde_yaml::to_string(&root_sig).unwrap().trim(), + "root-verity-sig" + ); for dpt in [ DiscoverablePartitionType::RootVeritySig, DiscoverablePartitionType::RootAmd64VeritySig, DiscoverablePartitionType::RootArm64VeritySig, ] { - assert!(matches!( - PartitionType::from(dpt), - PartitionType::Unknown(_) - )); + assert_eq!(PartitionType::from(dpt), PartitionType::RootVeritySig); } } diff --git a/crates/trident_api/src/config/host/storage/storage_graph/rules/mod.rs b/crates/trident_api/src/config/host/storage/storage_graph/rules/mod.rs index f9fec356fd..3e188e9c2c 100644 --- a/crates/trident_api/src/config/host/storage/storage_graph/rules/mod.rs +++ b/crates/trident_api/src/config/host/storage/storage_graph/rules/mod.rs @@ -472,8 +472,10 @@ impl BlkDevReferrerKind { Self::VerityDevice => AllowBlockList::Allow(vec![ PartitionType::Root, PartitionType::RootVerity, + PartitionType::RootVeritySig, PartitionType::Usr, PartitionType::UsrVerity, + PartitionType::UsrVeritySig, PartitionType::LinuxGeneric, // Special case for ACL. PartitionType::acl_usr(), @@ -504,12 +506,11 @@ impl SpecialReferenceKind { PartitionType::LinuxGeneric, ])), - // There is no standard discoverable partition type GUID for a - // verity root hash signature partition, so only a generic Linux - // partition type is allowed. - Self::VerityHashSignatureDevice => { - Some(AllowBlockList::Allow(vec![PartitionType::LinuxGeneric])) - } + Self::VerityHashSignatureDevice => Some(AllowBlockList::Allow(vec![ + PartitionType::RootVeritySig, + PartitionType::UsrVeritySig, + PartitionType::LinuxGeneric, + ])), } } } @@ -535,6 +536,7 @@ impl PartitionType { Self::LinuxGeneric => AllowBlockList::Any, Self::Root => AllowBlockList::new_allow(["/"]), Self::RootVerity => AllowBlockList::None, + Self::RootVeritySig => AllowBlockList::None, Self::Srv => AllowBlockList::new_allow(["/srv"]), Self::Swap => AllowBlockList::None, Self::Tmp => AllowBlockList::new_allow(["/var/tmp"]), @@ -602,3 +604,34 @@ impl BlkDevReferrerKind { Ok(()) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn signature_partition_types_match_hash_policy() { + let signature_types = SpecialReferenceKind::VerityHashSignatureDevice + .allowed_partition_types() + .unwrap(); + let verity_types = BlkDevReferrerKind::VerityDevice.allowed_partition_types(); + for partition_type in [ + PartitionType::RootVeritySig, + PartitionType::UsrVeritySig, + PartitionType::LinuxGeneric, + ] { + assert!(signature_types.contains(partition_type), "{partition_type}"); + assert!(verity_types.contains(partition_type), "{partition_type}"); + } + for partition_type in [ + PartitionType::Esp, + PartitionType::RootVerity, + PartitionType::UsrVerity, + ] { + assert!( + !signature_types.contains(partition_type), + "{partition_type}" + ); + } + } +} diff --git a/docs/Reference/Host-Configuration/API-Reference/PartitionType.md b/docs/Reference/Host-Configuration/API-Reference/PartitionType.md index 62028a2fbf..0259e8a317 100644 --- a/docs/Reference/Host-Configuration/API-Reference/PartitionType.md +++ b/docs/Reference/Host-Configuration/API-Reference/PartitionType.md @@ -52,6 +52,15 @@ x64: `2c7357ed-ebd2-46d9-aec1-23d437ec2bf5` | Type | `string` | | Value | `root-verity` | +### Root verity hash signature partition + +x64: `41092b05-9fc8-4523-994f-2def0408b176` + +| Characteristic | Value | +| -------------- | ----------------- | +| Type | `string` | +| Value | `root-verity-sig` | + ### Home partition `933ac7e1-2eb4-4f13-b844-0e14e2aef915` diff --git a/docs/Reference/Host-Configuration/Storage-Rules.md b/docs/Reference/Host-Configuration/Storage-Rules.md index 09a80ffdf1..f6ff61371a 100644 --- a/docs/Reference/Host-Configuration/Storage-Rules.md +++ b/docs/Reference/Host-Configuration/Storage-Rules.md @@ -199,17 +199,17 @@ The following referrers require that all underlying partitions are of the same s Some referrers only support specific underlying partitions types. -| Referrer type | Allowed partition types | -| ------------------ | -------------------------------------------------------------------------- | -| raid-array | any | -| ab-volume | any | -| encrypted-volume | any type except 'esp' or 'root' or 'root-verity' or 'usr-verity' or 'home' | -| verity-device | 'root' or 'root-verity' or 'usr' or 'usr-verity' or 'linux-generic' | -| swap-device | 'swap' | -| filesystem-new | any type except 'esp' | -| filesystem-image | any | -| filesystem-esp | 'esp' | -| filesystem-adopted | any type except 'esp' | +| Referrer type | Allowed partition types | +| ------------------ | ------------------------------------------------------------------------------------------------------------ | +| raid-array | any | +| ab-volume | any | +| encrypted-volume | any type except 'esp' or 'root' or 'root-verity' or 'usr-verity' or 'home' | +| verity-device | 'root' or 'root-verity' or 'root-verity-sig' or 'usr' or 'usr-verity' or 'usr-verity-sig' or 'linux-generic' | +| swap-device | 'swap' | +| filesystem-new | any type except 'esp' | +| filesystem-image | any | +| filesystem-esp | 'esp' | +| filesystem-adopted | any type except 'esp' | ## Allowed RAID Levels @@ -239,22 +239,23 @@ The following table lists the expected mount points for each partition type, as defined in the [Discoverable Partition Specification (DPS)](https://uapi-group.org/specifications/specs/discoverable_partitions_specification/): -| Partition Type | Valid Mount Paths | -| -------------- | -------------------------------- | -| esp | `/boot` or `/efi` or `/boot/efi` | -| root | `/` | -| swap | None | -| root-verity | None | -| home | `/home` | -| var | `/var` | -| usr | `/usr` | -| usr-verity | None | -| usr-verity-sig | None | -| tmp | `/var/tmp` | -| linux-generic | Any path | -| srv | `/srv` | -| xbootldr | `/boot` | -| unknown | Any path | +| Partition Type | Valid Mount Paths | +| --------------- | -------------------------------- | +| esp | `/boot` or `/efi` or `/boot/efi` | +| root | `/` | +| swap | None | +| root-verity | None | +| root-verity-sig | None | +| home | `/home` | +| var | `/var` | +| usr | `/usr` | +| usr-verity | None | +| usr-verity-sig | None | +| tmp | `/var/tmp` | +| linux-generic | Any path | +| srv | `/srv` | +| xbootldr | `/boot` | +| unknown | Any path | ## Partition Type Matching Hash Partition