From 7fbf80c75b08a5fbdffbb12a978e1d2e5ee0d81b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20B=C4=99za?= Date: Fri, 15 May 2026 14:21:21 +0200 Subject: [PATCH] refactor(attestation-types): move DstackAttestation, Collateral, QuoteBytes into the no-dcap-qvl crate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pure crate split, no behavior change. Sets up the next PR to drop `dcap-qvl` from `mpc-contract`'s WASM build graph (currently `mpc-contract -> mpc-attestation -> attestation -> dcap-qvl`). What moves into `attestation-types`: - `DstackAttestation` — the wasm-friendly bundle struct (`quote`, `collateral`, `tcb_info`). No methods on the struct itself; the `dcap_qvl::verify::verify` entry point is a trait method on the `attestation` side. - `Collateral` — field-for-field mirror of `dcap_qvl::QuoteCollateralV3`. Borsh wire layout matches the upstream type when `dcap-qvl` is built with its `borsh` feature, so on-chain state that previously stored an `attestation::collateral::Collateral` (newtype around `dcap_qvl::QuoteCollateralV3`) decodes into this type byte-identical without migration. - `QuoteBytes` — unchanged. What stays in `attestation`: - `DstackVerify` trait + `impl DstackVerify for DstackAttestation`, which is the one and only `dcap_qvl::verify::verify` call site. Defined as a trait because inherent impls on foreign types are forbidden in Rust. - `collateral_from_dcap` / `collateral_to_dcap` free functions for converting between `dcap_qvl::QuoteCollateralV3` and the mirror. Used by off-chain code (`tee-authority`'s PCCS fetch path, integration tests) and re-exported through `mpc_attestation` so the call sites don't need to add a direct `attestation` dep. Why a trait instead of an inherent method: - The `DstackAttestation` struct lives in `attestation-types`. - The `verify` method requires `dcap-qvl` (heavy crypto closure). - Rust forbids inherent impls on foreign types. A trait lets the `verify` method be added from the `attestation` crate (which has the `dcap-qvl` dep) to the type defined in `attestation-types` (which doesn't). Callers using `dstack_attestation.verify(...)` syntax now need to bring `DstackVerify` into scope. `mpc-attestation` does this internally; no other consumers were affected. Drive-bys: - `mpc-attestation::collateral_from_dcap` / `mpc_attestation::collateral_to_dcap` re-exports so `tee-authority` and `mpc-node` can call them without adding an `attestation` direct dep. - `IntoContractType` / `IntoInterfaceType` impls in `mpc-contract` and `mpc-node` simplified to direct field assignment (no more `Collateral::from(QuoteCollateralV3 { ... })`). - `attestation` crate's deps pruned: drops `borsh`, `derive_more`, `serde`, `hex`, `thiserror` (no longer used after the body shrank to the trait + conversion helpers); `serde_json` moved to dev-deps. WASM size impact (non-reproducible release-contract profile): 1,470,007 → 1,471,144 bytes (+1,137 bytes / 0.07%). Negligible — the next PR drops `dcap-qvl` from the contract entirely. Stacked on #3245. --- Cargo.lock | 5 - .../src/collateral.rs | 61 ++++++----- .../src/dstack_attestation.rs | 48 +++++++++ crates/attestation-types/src/lib.rs | 3 + crates/attestation-types/src/quote.rs | 31 ++++++ crates/attestation/Cargo.toml | 11 +- crates/attestation/src/attestation.rs | 102 ++++++++---------- crates/attestation/src/lib.rs | 69 ++++++++++-- crates/attestation/src/quote.rs | 22 ---- crates/attestation/tests/collateral.rs | 12 +-- crates/contract/src/dto_mapping.rs | 11 +- crates/mpc-attestation/src/attestation.rs | 2 +- crates/mpc-attestation/src/lib.rs | 2 +- .../convert_to_contract_dto.rs | 7 +- crates/tee-authority/src/tee_authority.rs | 14 ++- 15 files changed, 247 insertions(+), 153 deletions(-) rename crates/{attestation => attestation-types}/src/collateral.rs (67%) create mode 100644 crates/attestation-types/src/dstack_attestation.rs create mode 100644 crates/attestation-types/src/quote.rs delete mode 100644 crates/attestation/src/quote.rs diff --git a/Cargo.lock b/Cargo.lock index a28350b22d..6ff59caf8c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -968,16 +968,11 @@ version = "3.9.0" dependencies = [ "assert_matches", "attestation-types", - "borsh", "dcap-qvl", - "derive_more 2.1.1", "dstack-sdk-types", - "hex", - "serde", "serde_json", "tee-verifier-interface", "test-utils", - "thiserror 2.0.18", ] [[package]] diff --git a/crates/attestation/src/collateral.rs b/crates/attestation-types/src/collateral.rs similarity index 67% rename from crates/attestation/src/collateral.rs rename to crates/attestation-types/src/collateral.rs index 48514d9bcf..66c7799194 100644 --- a/crates/attestation/src/collateral.rs +++ b/crates/attestation-types/src/collateral.rs @@ -1,26 +1,44 @@ +//! `Collateral` — Borsh-stable mirror of `dcap_qvl::QuoteCollateralV3`. +//! +//! Field-for-field copy. Borsh wire layout matches the upstream type when +//! `dcap-qvl` is built with its `borsh` feature, so on-chain state that +//! previously stored an `attestation::collateral::Collateral` (newtype +//! wrapping `dcap_qvl::QuoteCollateralV3`) decodes into this type with no +//! migration. +//! +//! The conversion to/from `dcap_qvl::QuoteCollateralV3` lives in the +//! `attestation` crate (it depends on `dcap-qvl`); this crate does not. + +use alloc::{string::String, vec::Vec}; use borsh::{BorshDeserialize, BorshSerialize}; -use derive_more::{Deref, From, Into}; use serde::{Deserialize, Serialize}; -#[cfg(feature = "test-utils")] -use { - alloc::{string::String, vec::Vec}, - core::str::FromStr, - hex::FromHexError, - serde_json::Value, - thiserror::Error, -}; +// `BorshSchema` derive expands to `T::declaration().to_string()`, which is +// only in scope under no_std when `alloc::string::ToString` is imported. +#[cfg(feature = "borsh-schema")] +use alloc::string::ToString as _; -pub use dcap_qvl::QuoteCollateralV3; +#[cfg(feature = "test-utils")] +use {core::str::FromStr, hex::FromHexError, serde_json::Value, thiserror::Error}; /// Supplemental data for the TEE quote, including Intel certificates to verify it came from genuine /// Intel hardware, along with details about the Trusted Computing Base (TCB) versioning, status, /// and other relevant info. -#[derive( - Clone, From, Deref, Into, Debug, Serialize, Deserialize, BorshSerialize, BorshDeserialize, -)] +#[derive(Clone, Debug, Serialize, Deserialize, BorshSerialize, BorshDeserialize, PartialEq, Eq)] +#[cfg_attr(feature = "borsh-schema", derive(borsh::BorshSchema))] #[cfg_attr(feature = "test-utils", serde(try_from = "Value"))] -pub struct Collateral(QuoteCollateralV3); +pub struct Collateral { + pub pck_crl_issuer_chain: String, + pub root_ca_crl: Vec, + pub pck_crl: Vec, + pub tcb_info_issuer_chain: String, + pub tcb_info: String, + pub tcb_info_signature: Vec, + pub qe_identity_issuer_chain: String, + pub qe_identity: String, + pub qe_identity_signature: Vec, + pub pck_certificate_chain: Option, +} #[cfg(feature = "test-utils")] impl Collateral { @@ -47,7 +65,7 @@ impl Collateral { }) } - let quote_collateral = QuoteCollateralV3 { + Ok(Self { tcb_info_issuer_chain: get_str(&v, "tcb_info_issuer_chain")?, tcb_info: get_str(&v, "tcb_info")?, tcb_info_signature: get_hex(&v, "tcb_info_signature")?, @@ -58,8 +76,7 @@ impl Collateral { root_ca_crl: get_hex(&v, "root_ca_crl")?, pck_crl: get_hex(&v, "pck_crl")?, pck_certificate_chain: get_str(&v, "pck_certificate_chain").ok(), - }; - Ok(Self(quote_collateral)) + }) } } @@ -68,16 +85,6 @@ impl FromStr for Collateral { type Err = CollateralError; /// Attempts to parse a JSON string into a [`Collateral`]. - /// - /// This is a convenience method that first parses the string as JSON, then attempts to convert - /// it to a [`Collateral`]. - /// - /// # Errors - /// - /// Returns a [`CollateralError`] if: - /// - The string is not valid JSON - /// - The JSON doesn't contain the required collateral fields - /// - Hex fields cannot be decoded fn from_str(s: &str) -> Result { let json_value: Value = serde_json::from_str(s).map_err(|_| CollateralError::InvalidJson)?; diff --git a/crates/attestation-types/src/dstack_attestation.rs b/crates/attestation-types/src/dstack_attestation.rs new file mode 100644 index 0000000000..4cfeed4b8a --- /dev/null +++ b/crates/attestation-types/src/dstack_attestation.rs @@ -0,0 +1,48 @@ +//! `DstackAttestation` — the bundle a TDX node submits for verification. +//! +//! Holds the raw quote bytes, the Intel collateral required to verify +//! them, and the Dstack-supplied TCB info. This crate carries only the +//! data shape; the `dcap_qvl::verify::verify` call that consumes a +//! `(quote, collateral)` pair lives in the `attestation` crate (which is +//! the only crate that depends on `dcap-qvl`). + +use borsh::{BorshDeserialize, BorshSerialize}; +use core::fmt; +use derive_more::Constructor; +use serde::{Deserialize, Serialize}; + +use alloc::{format, string::String}; + +use crate::{collateral::Collateral, quote::QuoteBytes, tcb_info::TcbInfo}; + +#[derive(Clone, Constructor, Serialize, Deserialize, BorshDeserialize, BorshSerialize)] +pub struct DstackAttestation { + pub quote: QuoteBytes, + pub collateral: Collateral, + pub tcb_info: TcbInfo, +} + +impl fmt::Debug for DstackAttestation { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + const MAX_BYTES: usize = 2048; + + fn truncate_debug(value: &T, max_bytes: usize) -> String { + let debug_str = format!("{:?}", value); + if debug_str.len() <= max_bytes { + debug_str + } else { + format!( + "{}... (truncated {} bytes)", + &debug_str[..max_bytes], + debug_str.len() - max_bytes + ) + } + } + + f.debug_struct("DstackAttestation") + .field("quote", &truncate_debug(&self.quote, MAX_BYTES)) + .field("collateral", &truncate_debug(&self.collateral, MAX_BYTES)) + .field("tcb_info", &truncate_debug(&self.tcb_info, MAX_BYTES)) + .finish() + } +} diff --git a/crates/attestation-types/src/lib.rs b/crates/attestation-types/src/lib.rs index fe3e17269b..97c3acca48 100644 --- a/crates/attestation-types/src/lib.rs +++ b/crates/attestation-types/src/lib.rs @@ -23,7 +23,10 @@ extern crate alloc; pub mod app_compose; +pub mod collateral; +pub mod dstack_attestation; pub mod measurements; +pub mod quote; pub mod report_data; pub mod tcb_info; pub mod verify_post_dcap; diff --git a/crates/attestation-types/src/quote.rs b/crates/attestation-types/src/quote.rs new file mode 100644 index 0000000000..7497e48257 --- /dev/null +++ b/crates/attestation-types/src/quote.rs @@ -0,0 +1,31 @@ +use alloc::vec::Vec; +use borsh::{BorshDeserialize, BorshSerialize}; +use derive_more::{Deref, From, Into}; +use serde::{Deserialize, Serialize}; + +// `BorshSchema` derive expands to `T::declaration().to_string()`, which is +// only in scope under no_std when `alloc::string::ToString` is imported. +#[cfg(feature = "borsh-schema")] +use alloc::string::ToString as _; + +/// Raw bytes of an Intel TDX / SGX quote, as produced by the platform. +/// +/// Borsh-encoded as a length-prefixed byte vector. Identical wire layout to +/// `dcap_qvl::verify::verify`'s first argument. +#[derive( + Debug, + Clone, + From, + Into, + Deref, + Serialize, + Deserialize, + BorshDeserialize, + BorshSerialize, + PartialEq, + Eq, + PartialOrd, + Ord, +)] +#[cfg_attr(feature = "borsh-schema", derive(borsh::BorshSchema))] +pub struct QuoteBytes(Vec); diff --git a/crates/attestation/Cargo.toml b/crates/attestation/Cargo.toml index 7af0a4e191..4fb9b88bcf 100644 --- a/crates/attestation/Cargo.toml +++ b/crates/attestation/Cargo.toml @@ -5,24 +5,19 @@ license = { workspace = true } edition = { workspace = true } [features] -borsh-schema = ["borsh/unstable__schema", "attestation-types/borsh-schema"] +borsh-schema = ["attestation-types/borsh-schema"] dstack-conversions = ["attestation-types/dstack-conversions"] -test-utils = [] +test-utils = ["attestation-types/test-utils"] [dependencies] attestation-types = { workspace = true } -borsh = { workspace = true } dcap-qvl = { workspace = true } -derive_more = { workspace = true } -hex = { workspace = true } -serde = { workspace = true } -serde_json = { workspace = true } tee-verifier-interface = { workspace = true } -thiserror = { workspace = true } [dev-dependencies] assert_matches = { workspace = true } dstack-sdk-types = { workspace = true } +serde_json = { workspace = true } test-utils = { workspace = true } [[test]] diff --git a/crates/attestation/src/attestation.rs b/crates/attestation/src/attestation.rs index 1667a26613..162a87b5c5 100644 --- a/crates/attestation/src/attestation.rs +++ b/crates/attestation/src/attestation.rs @@ -1,90 +1,78 @@ //! Local off-chain TEE attestation verification. //! -//! Carries the `DstackAttestation` struct and its [`DstackAttestation::verify`] -//! method, which is the *only* place the heavy `dcap_qvl::verify::verify` -//! cryptographic call is made. After that call, the parsed report is -//! converted to the [`tee_verifier_interface::VerifiedReport`] mirror and -//! the post-DCAP checks are run via the free functions in +//! Adds the [`DstackVerify::verify`] trait method to the wasm-friendly +//! `DstackAttestation` struct that lives in `attestation-types`. The +//! `verify` implementation is the *only* place the heavy +//! `dcap_qvl::verify::verify` cryptographic call is made. After that +//! call, the parsed report is converted to the +//! [`tee_verifier_interface::VerifiedReport`] mirror and the post-DCAP +//! checks are run via the free functions in //! [`attestation_types::verify_post_dcap`] — same code path the //! `tee-verifier` contract uses on its callback side. //! //! Consumers that don't need to run `dcap-qvl` locally should depend on //! `attestation-types` directly, not this crate. -use alloc::{ - format, - string::{String, ToString}, -}; -use borsh::{BorshDeserialize, BorshSerialize}; -use core::fmt; -use derive_more::Constructor; -use serde::{Deserialize, Serialize}; +use alloc::string::ToString; use attestation_types::{ measurements::ExpectedMeasurements, report_data::ReportData, - tcb_info::TcbInfo, verify_post_dcap::{ verify_any_measurements, verify_app_compose, verify_report_data, verify_rtmr3, verify_tcb_status, }, }; -// Re-export the post-DCAP helper traits and the error type at the historical -// `attestation::attestation::*` paths so existing consumers (e.g. -// `mpc-attestation`) keep working without import-path churn. +// Re-export the post-DCAP helper traits, the error type, and +// `DstackAttestation` itself at the historical +// `attestation::attestation::*` paths so existing consumers +// (e.g. `mpc-attestation`) keep working without import-path churn. +// `DstackAttestation` now lives in `attestation-types`; the +// `dcap_qvl::verify::verify` entry point is provided as an inherent +// extension via the [`DstackVerify`] trait below (Rust forbids inherent +// impls on foreign types, so a trait is the only way to add the method +// from this crate). +pub use attestation_types::dstack_attestation::DstackAttestation; pub use attestation_types::verify_post_dcap::{GetSingleEvent, OrErr, VerificationError}; -use crate::{collateral::Collateral, quote::QuoteBytes}; - -#[derive(Clone, Constructor, Serialize, Deserialize, BorshDeserialize, BorshSerialize)] -pub struct DstackAttestation { - pub quote: QuoteBytes, - pub collateral: Collateral, - pub tcb_info: TcbInfo, -} - -impl fmt::Debug for DstackAttestation { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - const MAX_BYTES: usize = 2048; - - fn truncate_debug(value: &T, max_bytes: usize) -> String { - let debug_str = format!("{:?}", value); - if debug_str.len() <= max_bytes { - debug_str - } else { - format!( - "{}... (truncated {} bytes)", - &debug_str[..max_bytes], - debug_str.len() - max_bytes - ) - } - } - - f.debug_struct("DstackAttestation") - .field("quote", &truncate_debug(&self.quote, MAX_BYTES)) - .field("collateral", &truncate_debug(&self.collateral, MAX_BYTES)) - .field("tcb_info", &truncate_debug(&self.tcb_info, MAX_BYTES)) - .finish() - } -} - -impl DstackAttestation { - /// Checks whether this attestation is valid with respect to expected values of: +/// Local `dcap_qvl::verify::verify` entry point on `DstackAttestation`. +/// +/// Implemented for `attestation_types::dstack_attestation::DstackAttestation` +/// in this crate, which is the only crate that depends on `dcap-qvl`. +/// Defined as a trait because inherent impls on foreign types are not +/// allowed in Rust. +pub trait DstackVerify { + /// Checks whether this attestation is valid with respect to expected + /// values of: /// - `expected_report_data`: must be measured correctly in RTMR3 /// - `timestamp_seconds`: current UNIX time in seconds - /// - `accepted_measurements`: set of accepted RTMRs and key-provider event digest. - /// If any element in the set is valid, the function accepts the attestation as valid. + /// - `accepted_measurements`: set of accepted RTMRs and key-provider + /// event digest. If any element in the set is valid, the function + /// accepts the attestation as valid. /// /// On success, returns the matched measurements. - pub fn verify( + fn verify( + &self, + expected_report_data: ReportData, + timestamp_seconds: u64, + accepted_measurements: &[ExpectedMeasurements], + ) -> Result; +} + +impl DstackVerify for DstackAttestation { + fn verify( &self, expected_report_data: ReportData, timestamp_seconds: u64, accepted_measurements: &[ExpectedMeasurements], ) -> Result { + // The local-verify path constructs a fresh `QuoteCollateralV3` from + // the wasm-friendly mirror by cloning. The cost is negligible + // (a handful of String / Vec clones) and only paid off-chain. + let collateral = crate::collateral_to_dcap(self.collateral.clone()); let verification_result = - dcap_qvl::verify::verify(&self.quote, &self.collateral, timestamp_seconds) + dcap_qvl::verify::verify(&self.quote, &collateral, timestamp_seconds) .map_err(|e| VerificationError::DcapVerification(e.to_string()))?; let verified_report = to_mirror_verified_report(verification_result); diff --git a/crates/attestation/src/lib.rs b/crates/attestation/src/lib.rs index 0b0366ebba..aed90e3155 100644 --- a/crates/attestation/src/lib.rs +++ b/crates/attestation/src/lib.rs @@ -3,11 +3,64 @@ extern crate alloc; pub mod attestation; -pub mod collateral; -pub mod quote; - -// DTOs and post-DCAP helpers live in `attestation-types`. Re-exported here -// so existing consumers can keep using paths like `attestation::tcb_info` -// without churn. The `attestation` crate adds only the `dcap_qvl::verify` -// entry point (`DstackAttestation::verify`) on top. -pub use attestation_types::{app_compose, measurements, report_data, tcb_info, verify_post_dcap}; + +// All DTOs and post-DCAP helpers live in `attestation-types`. The +// `attestation` crate exists only to host `DstackAttestation::verify` +// (the local `dcap_qvl::verify::verify` call site) and the conversion +// helpers between `attestation-types` shapes and the `dcap_qvl` upstream +// types. +// +// Re-export the modules at the historical `attestation::*` paths so +// existing consumers keep their imports. +pub use attestation_types::{ + app_compose, collateral, dstack_attestation, measurements, quote, report_data, tcb_info, + verify_post_dcap, +}; + +/// Convenience re-export so existing code that imports +/// `attestation::collateral::Collateral` keeps compiling. +pub use attestation_types::collateral::Collateral; + +/// Convenience re-export so existing code that imports +/// `attestation::quote::QuoteBytes` keeps compiling. +pub use attestation_types::quote::QuoteBytes; + +/// Convert a `dcap_qvl::QuoteCollateralV3` into the wasm-friendly +/// `attestation_types::Collateral` mirror. +/// +/// Used by off-chain code (e.g. `tee-authority`) that fetches collateral +/// via `dcap_qvl::collateral::CollateralClient`. Lives here rather than +/// as a `From` impl because the orphan rule forbids implementing a +/// foreign trait between two foreign types from a third crate. +pub fn collateral_from_dcap(value: dcap_qvl::QuoteCollateralV3) -> Collateral { + Collateral { + pck_crl_issuer_chain: value.pck_crl_issuer_chain, + root_ca_crl: value.root_ca_crl, + pck_crl: value.pck_crl, + tcb_info_issuer_chain: value.tcb_info_issuer_chain, + tcb_info: value.tcb_info, + tcb_info_signature: value.tcb_info_signature, + qe_identity_issuer_chain: value.qe_identity_issuer_chain, + qe_identity: value.qe_identity, + qe_identity_signature: value.qe_identity_signature, + pck_certificate_chain: value.pck_certificate_chain, + } +} + +/// Convert an `attestation_types::Collateral` mirror into the +/// `dcap_qvl::QuoteCollateralV3` shape that `dcap_qvl::verify::verify` +/// consumes. +pub fn collateral_to_dcap(value: Collateral) -> dcap_qvl::QuoteCollateralV3 { + dcap_qvl::QuoteCollateralV3 { + pck_crl_issuer_chain: value.pck_crl_issuer_chain, + root_ca_crl: value.root_ca_crl, + pck_crl: value.pck_crl, + tcb_info_issuer_chain: value.tcb_info_issuer_chain, + tcb_info: value.tcb_info, + tcb_info_signature: value.tcb_info_signature, + qe_identity_issuer_chain: value.qe_identity_issuer_chain, + qe_identity: value.qe_identity, + qe_identity_signature: value.qe_identity_signature, + pck_certificate_chain: value.pck_certificate_chain, + } +} diff --git a/crates/attestation/src/quote.rs b/crates/attestation/src/quote.rs deleted file mode 100644 index 826162eff9..0000000000 --- a/crates/attestation/src/quote.rs +++ /dev/null @@ -1,22 +0,0 @@ -use alloc::vec::Vec; -use borsh::{BorshDeserialize, BorshSerialize}; -use derive_more::{Deref, From, Into}; -use serde::{Deserialize, Serialize}; - -#[derive( - Debug, - Clone, - From, - Into, - Deref, - Serialize, - Deserialize, - BorshDeserialize, - BorshSerialize, - PartialEq, - Eq, - PartialOrd, - Ord, -)] - -pub struct QuoteBytes(Vec); diff --git a/crates/attestation/tests/collateral.rs b/crates/attestation/tests/collateral.rs index e56350f3c7..c8468ebc7e 100644 --- a/crates/attestation/tests/collateral.rs +++ b/crates/attestation/tests/collateral.rs @@ -2,7 +2,7 @@ use std::str::FromStr; use assert_matches::assert_matches; use attestation::collateral::{Collateral, CollateralError}; -use dcap_qvl::QuoteCollateralV3; +use attestation::{collateral_from_dcap, collateral_to_dcap}; use serde_json::json; use test_utils::attestation::collateral; @@ -70,16 +70,16 @@ fn test_hex_signature_lengths() { } #[test] -fn test_derive_traits() { +fn test_collateral_dcap_round_trip() { let json_value = collateral(); let collateral = Collateral::try_from_json(json_value.clone()).unwrap(); - // Test From trait (should work through derive_more) - let quote_collateral_v3: QuoteCollateralV3 = collateral.into(); + // mirror -> dcap_qvl type + let quote_collateral_v3 = collateral_to_dcap(collateral); assert!(quote_collateral_v3.tcb_info.contains("\"id\":\"TDX\"")); - // Test creating from QuoteCollateralV3 - let new_collateral = Collateral::from(quote_collateral_v3); + // dcap_qvl type -> mirror + let new_collateral = collateral_from_dcap(quote_collateral_v3); assert!(new_collateral.tcb_info.contains("\"id\":\"TDX\"")); } diff --git a/crates/contract/src/dto_mapping.rs b/crates/contract/src/dto_mapping.rs index dd8ad67f07..3e7af6a816 100644 --- a/crates/contract/src/dto_mapping.rs +++ b/crates/contract/src/dto_mapping.rs @@ -10,7 +10,7 @@ use mpc_attestation::{ Attestation, DstackAttestation, ExpectedMeasurements, Measurements, MockAttestation, VerifiedAttestation, }, - collateral::{Collateral, QuoteCollateralV3}, + collateral::Collateral, tcb_info::{EventLog, HexBytes, TcbInfo}, }; use near_mpc_contract_interface::types as dtos; @@ -124,7 +124,7 @@ impl IntoContractType for dtos::Collateral { pck_certificate_chain, } = self; - Collateral::from(QuoteCollateralV3 { + Collateral { pck_crl_issuer_chain, root_ca_crl: root_ca_crl.into(), pck_crl: pck_crl.into(), @@ -135,7 +135,7 @@ impl IntoContractType for dtos::Collateral { qe_identity, qe_identity_signature: qe_identity_signature.into(), pck_certificate_chain, - }) + } } } @@ -311,8 +311,7 @@ impl IntoInterfaceType for DstackAttestation { impl IntoInterfaceType for Collateral { fn into_dto_type(self) -> dtos::Collateral { - // Collateral is a newtype wrapper around QuoteCollateralV3 - let QuoteCollateralV3 { + let Collateral { pck_crl_issuer_chain, root_ca_crl, pck_crl, @@ -323,7 +322,7 @@ impl IntoInterfaceType for Collateral { qe_identity, qe_identity_signature, pck_certificate_chain, - } = self.into(); + } = self; dtos::Collateral { pck_crl_issuer_chain, diff --git a/crates/mpc-attestation/src/attestation.rs b/crates/mpc-attestation/src/attestation.rs index 629b987674..0c29d90b4a 100644 --- a/crates/mpc-attestation/src/attestation.rs +++ b/crates/mpc-attestation/src/attestation.rs @@ -3,7 +3,7 @@ pub use attestation::attestation::{DstackAttestation, VerificationError}; pub use attestation::measurements::{ExpectedMeasurements, Measurements}; use attestation::{ app_compose::AppCompose, - attestation::{GetSingleEvent as _, OrErr as _}, + attestation::{DstackVerify as _, GetSingleEvent as _, OrErr as _}, report_data::ReportData, }; diff --git a/crates/mpc-attestation/src/lib.rs b/crates/mpc-attestation/src/lib.rs index 462ea2b6fc..6fac624fde 100644 --- a/crates/mpc-attestation/src/lib.rs +++ b/crates/mpc-attestation/src/lib.rs @@ -5,4 +5,4 @@ extern crate alloc; pub mod attestation; pub mod report_data; -pub use ::attestation::{collateral, quote, tcb_info}; +pub use ::attestation::{collateral, collateral_from_dcap, collateral_to_dcap, quote, tcb_info}; diff --git a/crates/node/src/trait_extensions/convert_to_contract_dto.rs b/crates/node/src/trait_extensions/convert_to_contract_dto.rs index 005ac1d833..46da16a43f 100644 --- a/crates/node/src/trait_extensions/convert_to_contract_dto.rs +++ b/crates/node/src/trait_extensions/convert_to_contract_dto.rs @@ -7,7 +7,7 @@ use mpc_attestation::{ attestation::{Attestation, DstackAttestation, MockAttestation}, - collateral::{Collateral, QuoteCollateralV3}, + collateral::Collateral, tcb_info::{EventLog, TcbInfo}, }; @@ -86,8 +86,7 @@ impl IntoContractInterfaceType for Collateral { fn into_contract_interface_type(self) -> near_mpc_contract_interface::types::Collateral { - // Collateral is a newtype wrapper around QuoteCollateralV3 - let QuoteCollateralV3 { + let Collateral { pck_crl_issuer_chain, root_ca_crl, pck_crl, @@ -98,7 +97,7 @@ impl IntoContractInterfaceType f qe_identity, qe_identity_signature, pck_certificate_chain, - } = self.into(); + } = self; near_mpc_contract_interface::types::Collateral { pck_crl_issuer_chain, diff --git a/crates/tee-authority/src/tee_authority.rs b/crates/tee-authority/src/tee_authority.rs index 2dd157b548..35861aae2b 100644 --- a/crates/tee-authority/src/tee_authority.rs +++ b/crates/tee-authority/src/tee_authority.rs @@ -495,7 +495,7 @@ impl TeeAuthority { url: endpoint.url.clone(), timeout: PCCS_REQUEST_TIMEOUT, })? - .map(Collateral::from) + .map(mpc_attestation::collateral_from_dcap) .map_err(|e| PccsEndpointError::Fetch { url: endpoint.url.clone(), source: anyhow::anyhow!(e), @@ -922,7 +922,7 @@ mod tests { /// inspected — it just needs to be a valid value that round-trips through /// the fetch path. fn dummy_collateral(tag: &str) -> Collateral { - dcap_qvl::QuoteCollateralV3 { + mpc_attestation::collateral_from_dcap(dcap_qvl::QuoteCollateralV3 { pck_crl_issuer_chain: tag.into(), root_ca_crl: Vec::new(), pck_crl: Vec::new(), @@ -933,8 +933,7 @@ mod tests { qe_identity: String::new(), qe_identity_signature: Vec::new(), pck_certificate_chain: None, - } - .into() + }) } fn endpoints(list: &[&str]) -> NonEmptyVec { @@ -1131,7 +1130,7 @@ mod tests { /// that exercise the JSON path get a fresh-enough CRL by virtue of /// the [`test_now`] choice. fn collateral_with_issue_dates(tcb_info_iso: &str, qe_identity_iso: &str) -> Collateral { - dcap_qvl::QuoteCollateralV3 { + mpc_attestation::collateral_from_dcap(dcap_qvl::QuoteCollateralV3 { pck_crl_issuer_chain: String::new(), root_ca_crl: Vec::new(), pck_crl: fixture_pck_crl(), @@ -1142,8 +1141,7 @@ mod tests { qe_identity: format!(r#"{{"issueDate":"{qe_identity_iso}"}}"#), qe_identity_signature: Vec::new(), pck_certificate_chain: None, - } - .into() + }) } /// Format an `OffsetDateTime` as RFC3339 (UTC) the way Intel PCS would @@ -1369,7 +1367,7 @@ mod tests { root_ca_crl, pck_crl, pck_certificate_chain, - }: dcap_qvl::QuoteCollateralV3 = collateral.into(); + } = mpc_attestation::collateral_to_dcap(collateral); assert!(!tcb_info_issuer_chain.is_empty()); assert!(!tcb_info.is_empty());