From c4d1275175a441b595c7519b7dc6e7e34bc51818 Mon Sep 17 00:00:00 2001 From: peg Date: Fri, 21 Aug 2026 10:41:42 +0200 Subject: [PATCH 1/2] Support portable measurement policies on bare metal --- crates/attestation/Cargo.toml | 4 +- crates/attestation/README.md | 30 ++-- crates/attestation/src/dcap.rs | 6 +- crates/attestation/src/gcp.rs | 3 + crates/attestation/src/lib.rs | 2 +- crates/attestation/src/measurements.rs | 191 +++++++++++++++++++------ 6 files changed, 175 insertions(+), 61 deletions(-) diff --git a/crates/attestation/Cargo.toml b/crates/attestation/Cargo.toml index 2a51288..ece3f81 100644 --- a/crates/attestation/Cargo.toml +++ b/crates/attestation/Cargo.toml @@ -13,8 +13,8 @@ pccs = { workspace = true } mock-tdx = { workspace = true, optional = true } tokio = { workspace = true, features = ["fs", "rt", "rt-multi-thread"] } tokio-rustls = { workspace = true, default-features = false } -attest-types = { git = "https://github.com/easy-tee/attest.git", rev = "8206cd19d9dcb1978d85a3d8dece06a3ee7a1206" } -attest-measure = {git = "https://github.com/easy-tee/attest.git", rev = "8206cd19d9dcb1978d85a3d8dece06a3ee7a1206" } +attest-types = { git = "https://github.com/easy-tee/attest.git", rev = "17d6d8b34c21db581da1a4829b2a9c0a113dd19d" } +attest-measure = { git = "https://github.com/easy-tee/attest.git", rev = "17d6d8b34c21db581da1a4829b2a9c0a113dd19d" } anyhow = "1.0.100" pem-rfc7468 = { version = "0.7.0", features = ["std"] } diff --git a/crates/attestation/README.md b/crates/attestation/README.md index 2fe0194..4aa793d 100644 --- a/crates/attestation/README.md +++ b/crates/attestation/README.md @@ -264,19 +264,22 @@ changes the expected register values even when the OS image is unchanged. The `dcap_image_hashes` alternative allows you to specify the OS image's boot-component hashes instead, and the verifier reconstructs the expected -register values from those hashes plus platform metadata fetched attest -verification time. The same policy record then matches the same OS images -across platform variants. +register values from those hashes plus platform metadata available at +attestation verification time. The same policy record then matches the same OS +images across platform variants. This can be done with the `attest measure` CLI from [Easy-TEE/attest](https://github.com/Easy-TEE/attest) which outputs five -hex-encoded SHA-384 values: +hex-encoded SHA-384 values and, for images using a recent systemd EFI stub, one +additional optional value: - `uki_authenticode` - authenticode hash of the UKI (unified kernel image) - `kernel_authenticode` - authenticode hash of the kernel binary - `cmdline_hash` - hash of the kernel command line - `initrd_hash` - hash of the initramfs - `gpt_disk_guid_hash` - hash derived from GPT partition GUIDs +- `pe_sections` - optional accumulated hash of the UKI PE sections measured by + recent systemd EFI stubs Example: @@ -284,7 +287,7 @@ Example: [ { "measurement_id": "flashbox-l1-v1.0.0", - "attestation_type": "gcp-tdx", + "attestation_type": "dcap-tdx", "dcap_image_hashes": { "uki_authenticode": "fcaceb6d87694746ba2d93a87ef4209f2a7629b7f400097b93241e80b9ec3e1e80f9a4cd8028e6a83f297ea5de8d9abc", "kernel_authenticode": "b6c5133268aa8b440509f3d53ee855a5cd3aeb6441eb109a9f27f14c43bce3e2383856df4af876501ceeb4c9a3b15f0c", @@ -298,17 +301,18 @@ Example: #### Supported attestation types for portable measurements -Portable policies currently only work with the `"gcp-tdx"` attestation type. -For GCP, the verifier fetches the platform firmware blob from Google's metadata -service (keyed by MRTD) and combines it with the image hashes to reconstruct the -expected registers. A `dcap_image_hashes` record with any other attestation type -is rejected when parsing from JSON. +Portable policies work with the `"dcap-tdx"` and `"gcp-tdx"` attestation types. +`"dcap-tdx"` accepts DCAP evidence from any platform, including GCP and +bare-metal TDX, while `"gcp-tdx"` restricts the record to GCP. For bare-metal +DCAP TDX, the verifier reconstructs and checks the image-dependent RTMR1 and +RTMR2 registers. For GCP, it additionally fetches the platform firmware blob +from Google's metadata service (keyed by MRTD) and reconstructs MRTD and RTMR0. The JSON object emitted directly by `attest measure portable` is also accepted as a measurement policy. Its optional `azure` PCR values and its `dcap` image -hashes are converted into Azure TDX and GCP TDX policy records respectively. -It can be supplied on its own or as an element of a policy array, including an -array mixed with records in the policy format described above: +hashes are converted into an Azure TDX record and a generic DCAP record +respectively. It can be supplied on its own or as an element of a policy array, +including an array mixed with records in the policy format described above: ```JSON { diff --git a/crates/attestation/src/dcap.rs b/crates/attestation/src/dcap.rs index fc88f22..4daaa87 100644 --- a/crates/attestation/src/dcap.rs +++ b/crates/attestation/src/dcap.rs @@ -358,7 +358,11 @@ mod tests { .unwrap(); assert_eq!(async_measurements, sync_measurements); - measurement_policy.check_measurement(&async_measurements, None).unwrap(); + let platform_metadata = + crate::mock_platform_metadata(crate::AttestationType::DcapTdx).unwrap(); + measurement_policy + .check_measurement(&async_measurements, Some(&platform_metadata)) + .unwrap(); } // This specifically tests a quote which has outdated TCB level from Azure diff --git a/crates/attestation/src/gcp.rs b/crates/attestation/src/gcp.rs index 28f8c1f..c0de23e 100644 --- a/crates/attestation/src/gcp.rs +++ b/crates/attestation/src/gcp.rs @@ -115,6 +115,7 @@ mod tests { gpt_disk_guid_hash: decode_dcap_hash( "488fa3f08aae01c1a46b497319e8a7d3b7335c9ff4f4d7fe6a3dd62c844b03de22157c0303be58f10e3152687778e68d", ), + pe_sections: None, } } @@ -168,6 +169,8 @@ mod tests { let measurement_policy = MeasurementPolicy { accepted_measurements: vec![MeasurementRecord { measurement_id: "gcp-tdx-portable-image-hashes".to_string(), + // The generic DCAP policy type accepts GCP DCAP evidence. + attestation_type: crate::AttestationType::DcapTdx, measurements: ExpectedMeasurements::Image(gcp_portable_image_hashes()), }], }; diff --git a/crates/attestation/src/lib.rs b/crates/attestation/src/lib.rs index da13d9d..3a7dbeb 100644 --- a/crates/attestation/src/lib.rs +++ b/crates/attestation/src/lib.rs @@ -766,7 +766,7 @@ mod tests { let quote = dcap::create_dcap_attestation(input_data).unwrap(); let attestation_evidence = AttestationEvidence { quote, - platform: mock_platform_metadata(AttestationType::GcpTdx).unwrap(), + platform: mock_platform_metadata(AttestationType::DcapTdx).unwrap(), }; let mock_pcs_server = spawn_mock_pcs_server(MockPcsConfig::default()).await.unwrap(); diff --git a/crates/attestation/src/measurements.rs b/crates/attestation/src/measurements.rs index 878ce87..c3ec525 100644 --- a/crates/attestation/src/measurements.rs +++ b/crates/attestation/src/measurements.rs @@ -211,6 +211,7 @@ impl fmt::Debug for AzureHexDebug<'_> { } /// Expected measurement values for policy enforcement +#[allow(clippy::large_enum_variant)] #[derive(Debug, Clone, PartialEq)] pub enum ExpectedMeasurements { Image(DcapImageHashes), @@ -319,14 +320,25 @@ pub struct MeasurementRecord { /// An identifier, for example the name and version of the corresponding /// OS image pub measurement_id: String, + /// The attestation platform this record accepts + pub attestation_type: AttestationType, /// The expected measurement register values pub measurements: ExpectedMeasurements, } impl MeasurementRecord { + fn accepts_attestation_type(&self, actual: AttestationType) -> bool { + self.attestation_type == actual || + matches!( + (self.attestation_type, actual), + (AttestationType::DcapTdx, AttestationType::GcpTdx) + ) + } + pub fn allow_no_attestation() -> Self { Self { measurement_id: "Allow no attestation".to_string(), + attestation_type: AttestationType::None, measurements: ExpectedMeasurements::NoAttestation, } } @@ -334,6 +346,7 @@ impl MeasurementRecord { pub fn allow_any_measurement(attestation_type: AttestationType) -> Self { Self { measurement_id: format!("Any measurement for {attestation_type}"), + attestation_type, measurements: match attestation_type { AttestationType::None => ExpectedMeasurements::NoAttestation, AttestationType::AzureTdx => ExpectedMeasurements::Azure(HashMap::new()), @@ -401,6 +414,7 @@ impl MeasurementPolicy { Self { accepted_measurements: vec![MeasurementRecord { measurement_id: "test".to_string(), + attestation_type: AttestationType::DcapTdx, measurements: ExpectedMeasurements::Dcap(HashMap::from([ (DcapMeasurementRegister::MRTD, vec![mock_tdx::MOCK_MRTD]), (DcapMeasurementRegister::RTMR0, vec![mock_tdx::MOCK_RTMR0]), @@ -431,7 +445,19 @@ impl MeasurementPolicy { platform_metadata: Option<&PlatformMetadata>, known_gcp_firmware: Option<&GcpFirmwareCache>, ) -> Result<(), AttestationError> { + let actual_attestation_type = match measurements { + MultiMeasurements::NoAttestation => Some(AttestationType::None), + MultiMeasurements::Dcap(_) | MultiMeasurements::Azure(_) => { + platform_metadata.map(|metadata| metadata.attestation_type.into()) + } + }; + + let Some(actual_attestation_type) = actual_attestation_type else { + return Err(AttestationError::MeasurementsNotAccepted); + }; + if self.accepted_measurements.iter().any(|measurement_record| match measurements { + _ if !measurement_record.accepts_attestation_type(actual_attestation_type) => false, MultiMeasurements::Dcap(dcap_measurements) => match &measurement_record.measurements { ExpectedMeasurements::Dcap(expected) => { // All measurements in our policy must be given and must match @@ -591,6 +617,7 @@ impl MeasurementPolicy { if let Some(azure) = portable.azure { measurement_policy.push(MeasurementRecord { measurement_id: String::new(), + attestation_type: AttestationType::AzureTdx, measurements: ExpectedMeasurements::Azure(HashMap::from([ (4, vec![azure.pcr4]), (9, vec![azure.pcr9]), @@ -601,12 +628,14 @@ impl MeasurementPolicy { measurement_policy.push(MeasurementRecord { measurement_id: String::new(), + attestation_type: AttestationType::DcapTdx, measurements: ExpectedMeasurements::Image(portable.dcap), }); } MeasurementOutput::Azure(azure) => { measurement_policy.push(MeasurementRecord { measurement_id: String::new(), + attestation_type: AttestationType::AzureTdx, measurements: ExpectedMeasurements::Azure(HashMap::from([ (4, vec![azure.pcr4]), (9, vec![azure.pcr9]), @@ -661,12 +690,10 @@ impl MeasurementPolicy { } }, (None, Some(image_hashes)) => match attestation_type { - // Currently only GCP is supported for portable measurement policy - but support - // for other types is planned - AttestationType::GcpTdx => ExpectedMeasurements::Image(image_hashes), - AttestationType::DcapTdx | - AttestationType::None | - AttestationType::AzureTdx => { + AttestationType::DcapTdx | AttestationType::GcpTdx => { + ExpectedMeasurements::Image(image_hashes) + } + AttestationType::None | AttestationType::AzureTdx => { return Err( MeasurementFormatError::DcapImageHashesUnsupportedAttestationType( record.attestation_type, @@ -683,6 +710,7 @@ impl MeasurementPolicy { measurement_policy.push(MeasurementRecord { measurement_id: record.measurement_id.unwrap_or_default(), + attestation_type, measurements: expected_measurements, }); } @@ -720,7 +748,8 @@ pub(crate) fn compare_portable_dcap_measurement( return false; }; - // On GCP, fetch the firmware associated with the MRTD + // GCP firmware is needed to reconstruct MRTD and RTMR0. For self-hosted + // TDX, a portable image policy reconstructs and checks RTMR1 and RTMR2. let firmware = match platform_metadata.attestation_type { ImageAttestationType::GcpTdx => { let mrtd = dcap_measurements.get(&DcapMeasurementRegister::MRTD); @@ -740,14 +769,7 @@ pub(crate) fn compare_portable_dcap_measurement( } } } - // These may be supported in the future but currently regarded as too - // experimental to work with 'portable' measurement policies - ImageAttestationType::SelfHostedTdx => { - warn!( - "Attempting to match portable measurement policy with bare metal TDX - not yet supported" - ); - return false; - } + ImageAttestationType::SelfHostedTdx => None, ImageAttestationType::AzureTdx => { warn!( "Attempting to match portable measurement policy with Azure TDX - not yet supported" @@ -766,23 +788,15 @@ pub(crate) fn compare_portable_dcap_measurement( } }; - if let Some(expected_mrtd) = expected_measurements.mrtd { - if dcap_measurements.get(&DcapMeasurementRegister::MRTD) != &expected_mrtd { - return false; - } - } else { - // This will only be the case with SelfHostedTdx which currently would - // already bail with the check above + if expected_measurements.mrtd.is_some_and(|expected_mrtd| { + dcap_measurements.get(&DcapMeasurementRegister::MRTD) != &expected_mrtd + }) { return false; } - if let Some(expected_rtmr0) = expected_measurements.rtmr0 { - if dcap_measurements.get(&DcapMeasurementRegister::RTMR0) != &expected_rtmr0 { - return false; - } - } else { - // This will only be the case with SelfHostedTdx which currently would - // already bail with the check above + if expected_measurements.rtmr0.is_some_and(|expected_rtmr0| { + dcap_measurements.get(&DcapMeasurementRegister::RTMR0) != &expected_rtmr0 + }) { return false; } @@ -854,6 +868,15 @@ mod tests { MultiMeasurements::Dcap(DcapMeasurements::new(mrtd, rtmr0, [0u8; 48], [0u8; 48], [0u8; 48])) } + fn self_hosted_platform_metadata() -> PlatformMetadata { + PlatformMetadata { + attestation_type: ImageAttestationType::SelfHostedTdx, + ram_bytes: 0, + num_disks: 0, + acpi: None, + } + } + /// MRTD from the pinned GCP firmware snapshot test asset const GCP_FIRMWARE_MRTD: &str = "feb7486608382c1ff0e15b4648ddc0acea6ca974eb53e3529f4c4bd5ffbaa20bf335cb75965cea65fe473aed9647c162"; @@ -963,7 +986,9 @@ mod tests { let allowed_attestation_type = MeasurementPolicy::from_file("test-assets/measurements_2.json".into()).await.unwrap(); - allowed_attestation_type.check_measurement(&mock_dcap_measurements(), None).unwrap(); + allowed_attestation_type + .check_measurement(&mock_dcap_measurements(), Some(&self_hosted_platform_metadata())) + .unwrap(); // Will not match another attestation type assert!(matches!( @@ -997,10 +1022,12 @@ mod tests { gpt_disk_guid_hash: decode_hash( "180bac1af9c35cc15e909623c005289539b4da2840d9c9b658fd4968ea4f03e0159402d03da1afc9035e0db30804e282", ), + pe_sections: None, }; let policy = MeasurementPolicy { accepted_measurements: vec![MeasurementRecord { measurement_id: "image-hash-policy".to_string(), + attestation_type: AttestationType::GcpTdx, measurements: ExpectedMeasurements::Image(image_hashes.clone()), }], }; @@ -1025,6 +1052,73 @@ mod tests { policy.check_measurement(&measurements, Some(&platform_metadata)).unwrap(); } + #[test] + fn test_bare_metal_image_hash_policy_checks_image_registers() { + let image_hashes = DcapImageHashes { + uki_authenticode: [0x11; 48], + kernel_authenticode: [0x22; 48], + cmdline_hash: [0x33; 48], + initrd_hash: [0x44; 48], + gpt_disk_guid_hash: [0x55; 48], + pe_sections: Some([0x66; 48]), + }; + let platform_metadata = PlatformMetadata { + attestation_type: ImageAttestationType::SelfHostedTdx, + ram_bytes: 0, + num_disks: 0, + acpi: None, + }; + let expected = expected_dcap_registers(&image_hashes, &platform_metadata, None).unwrap(); + let policy = MeasurementPolicy { + accepted_measurements: vec![MeasurementRecord { + measurement_id: "bare-metal-image-hash-policy".to_string(), + attestation_type: AttestationType::DcapTdx, + measurements: ExpectedMeasurements::Image(image_hashes), + }], + }; + let measurements = MultiMeasurements::Dcap(DcapMeasurements::new( + [0xaa; 48], + [0xbb; 48], + expected.rtmr1, + expected.rtmr2, + [0xcc; 48], + )); + + policy.check_measurement(&measurements, Some(&platform_metadata)).unwrap(); + + assert!(matches!( + policy.check_measurement(&measurements, None), + Err(AttestationError::MeasurementsNotAccepted) + )); + + let ExpectedMeasurements::Image(image_hashes) = + &policy.accepted_measurements[0].measurements + else { + unreachable!(); + }; + let gcp_policy = MeasurementPolicy { + accepted_measurements: vec![MeasurementRecord { + measurement_id: "gcp-image-hash-policy".to_string(), + attestation_type: AttestationType::GcpTdx, + measurements: ExpectedMeasurements::Image(image_hashes.clone()), + }], + }; + assert!(matches!( + gcp_policy.check_measurement(&measurements, Some(&platform_metadata)), + Err(AttestationError::MeasurementsNotAccepted) + )); + + let mut wrong_measurements = measurements.clone(); + let MultiMeasurements::Dcap(dcap) = &mut wrong_measurements else { + unreachable!(); + }; + dcap.rtmr2[0] ^= 1; + assert!(matches!( + policy.check_measurement(&wrong_measurements, Some(&platform_metadata)), + Err(AttestationError::MeasurementsNotAccepted) + )); + } + #[tokio::test] async fn test_buildernet_measurements() { // Refresh this fixture explicitly with: @@ -1122,28 +1216,32 @@ mod tests { async fn test_parse_image_hash_policy() { let json = r#"[ { - "measurement_id": "gcp-image-hash-example", - "attestation_type": "gcp-tdx", + "measurement_id": "bare-metal-image-hash-example", + "attestation_type": "dcap-tdx", "dcap_image_hashes": { "uki_authenticode": "fcaceb6d87694746ba2d93a87ef4209f2a7629b7f400097b93241e80b9ec3e1e80f9a4cd8028e6a83f297ea5de8d9abc", "kernel_authenticode": "b6c5133268aa8b440509f3d53ee855a5cd3aeb6441eb109a9f27f14c43bce3e2383856df4af876501ceeb4c9a3b15f0c", "cmdline_hash": "e03b89abf354a38976537b7a9138fd312e4cbf73b61eebc44086491701b1d167b9f6cb97a922325866c93e0834723d87", "initrd_hash": "a5b3d4742045e7d08aa19953c35098e784826b01a84f60568fa69f1a848dafd96ec98b8df616d6142779c9b97318166b", - "gpt_disk_guid_hash": "180bac1af9c35cc15e909623c005289539b4da2840d9c9b658fd4968ea4f03e0159402d03da1afc9035e0db30804e282" + "gpt_disk_guid_hash": "180bac1af9c35cc15e909623c005289539b4da2840d9c9b658fd4968ea4f03e0159402d03da1afc9035e0db30804e282", + "pe_sections": "111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" } } ]"#; let policy = MeasurementPolicy::from_json_bytes(json.as_bytes().to_vec()).unwrap(); assert_eq!(policy.accepted_measurements.len(), 1); - assert!(matches!( - policy.accepted_measurements[0].measurements, - ExpectedMeasurements::Image(_) - )); + assert_eq!(policy.accepted_measurements[0].attestation_type, AttestationType::DcapTdx); + let ExpectedMeasurements::Image(image_hashes) = + &policy.accepted_measurements[0].measurements + else { + panic!("expected portable DCAP image hashes"); + }; + assert_eq!(image_hashes.pe_sections, Some([0x11; 48])); } /// The object emitted by `attest measure portable` is accepted directly - /// and converted into Azure and GCP-compatible policy records. + /// and converted into Azure and DCAP-compatible policy records. #[test] fn test_parse_attest_measure_portable_output() { let json = r#"{ @@ -1167,6 +1265,7 @@ mod tests { let azure = &policy.accepted_measurements[0]; assert!(azure.measurement_id.is_empty()); + assert_eq!(azure.attestation_type, AttestationType::AzureTdx); let ExpectedMeasurements::Azure(registers) = &azure.measurements else { panic!("expected Azure measurements"); }; @@ -1179,6 +1278,7 @@ mod tests { let dcap = &policy.accepted_measurements[1]; assert!(dcap.measurement_id.is_empty()); + assert_eq!(dcap.attestation_type, AttestationType::DcapTdx); let ExpectedMeasurements::Image(image_hashes) = &dcap.measurements else { panic!("expected portable DCAP image hashes"); }; @@ -1208,6 +1308,7 @@ mod tests { let policy = MeasurementPolicy::from_json_bytes(json.as_bytes().to_vec()).unwrap(); assert_eq!(policy.accepted_measurements.len(), 1); + assert_eq!(policy.accepted_measurements[0].attestation_type, AttestationType::DcapTdx); assert!(matches!( policy.accepted_measurements[0].measurements, ExpectedMeasurements::Image(_) @@ -1393,18 +1494,19 @@ mod tests { ]"#; let policy = MeasurementPolicy::from_json_bytes(json.as_bytes().to_vec()).unwrap(); + let platform_metadata = self_hosted_platform_metadata(); // First value should match let measurements1 = test_dcap_measurements([0u8; 48], [0u8; 48]); - assert!(policy.check_measurement(&measurements1, None).is_ok()); + assert!(policy.check_measurement(&measurements1, Some(&platform_metadata)).is_ok()); // Second value should also match let measurements2 = test_dcap_measurements([0x11u8; 48], [0u8; 48]); - assert!(policy.check_measurement(&measurements2, None).is_ok()); + assert!(policy.check_measurement(&measurements2, Some(&platform_metadata)).is_ok()); // Different value should not match let measurements3 = test_dcap_measurements([0x22u8; 48], [0u8; 48]); - assert!(policy.check_measurement(&measurements3, None).is_err()); + assert!(policy.check_measurement(&measurements3, Some(&platform_metadata)).is_err()); } #[tokio::test] @@ -1478,18 +1580,19 @@ mod tests { ]"#; let policy = MeasurementPolicy::from_json_bytes(json.as_bytes().to_vec()).unwrap(); + let platform_metadata = self_hosted_platform_metadata(); // Both match (single + first of any) let measurements1 = test_dcap_measurements([0u8; 48], [0x11u8; 48]); - assert!(policy.check_measurement(&measurements1, None).is_ok()); + assert!(policy.check_measurement(&measurements1, Some(&platform_metadata)).is_ok()); // Both match (single + second of any) let measurements2 = test_dcap_measurements([0u8; 48], [0x22u8; 48]); - assert!(policy.check_measurement(&measurements2, None).is_ok()); + assert!(policy.check_measurement(&measurements2, Some(&platform_metadata)).is_ok()); // Single matches but any doesn't let measurements3 = test_dcap_measurements([0u8; 48], [0x33u8; 48]); - assert!(policy.check_measurement(&measurements3, None).is_err()); + assert!(policy.check_measurement(&measurements3, Some(&platform_metadata)).is_err()); } #[tokio::test] From eafa101221c7c1eac3792937758fae08906af5f5 Mon Sep 17 00:00:00 2001 From: peg Date: Fri, 21 Aug 2026 10:41:56 +0200 Subject: [PATCH 2/2] lockfile --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6349b80..5bdc8c6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -346,7 +346,7 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "attest-measure" version = "0.0.1" -source = "git+https://github.com/easy-tee/attest.git?rev=8206cd19d9dcb1978d85a3d8dece06a3ee7a1206#8206cd19d9dcb1978d85a3d8dece06a3ee7a1206" +source = "git+https://github.com/easy-tee/attest.git?rev=17d6d8b34c21db581da1a4829b2a9c0a113dd19d#17d6d8b34c21db581da1a4829b2a9c0a113dd19d" dependencies = [ "attest-types", "authenticode", @@ -371,7 +371,7 @@ dependencies = [ [[package]] name = "attest-types" version = "0.0.1" -source = "git+https://github.com/easy-tee/attest.git?rev=8206cd19d9dcb1978d85a3d8dece06a3ee7a1206#8206cd19d9dcb1978d85a3d8dece06a3ee7a1206" +source = "git+https://github.com/easy-tee/attest.git?rev=17d6d8b34c21db581da1a4829b2a9c0a113dd19d#17d6d8b34c21db581da1a4829b2a9c0a113dd19d" dependencies = [ "parity-scale-codec", "serde",