oasis_core_runtime/common/sgx/pcs/
policy.rs

1//! Quote policy.
2use super::{constants::*, report::TdReport, Error};
3
4/// Quote validity policy.
5#[derive(Clone, Debug, PartialEq, Eq, cbor::Encode, cbor::Decode)]
6pub struct QuotePolicy {
7    /// Whether PCS quotes are disabled and will always be rejected.
8    #[cbor(optional)]
9    pub disabled: bool,
10
11    /// Validity (in days) of the TCB collateral.
12    pub tcb_validity_period: u16,
13
14    /// Minimum TCB evaluation data number that is considered to be valid. TCB bundles containing
15    /// smaller values will be invalid.
16    pub min_tcb_evaluation_data_number: u32,
17
18    /// A list of hexadecimal encoded FMSPCs specifying which processor packages and platform
19    /// instances are blocked.
20    #[cbor(optional)]
21    pub fmspc_blacklist: Vec<String>,
22
23    /// Optional TDX-specific policy. In case this is `None`, TDX quotes are disallowed.
24    #[cbor(optional)]
25    pub tdx: Option<TdxQuotePolicy>,
26}
27
28impl Default for QuotePolicy {
29    fn default() -> Self {
30        Self {
31            disabled: false,
32            tcb_validity_period: 30,
33            min_tcb_evaluation_data_number: DEFAULT_MIN_TCB_EVALUATION_DATA_NUMBER,
34            fmspc_blacklist: Vec::new(),
35            tdx: None,
36        }
37    }
38}
39
40impl QuotePolicy {
41    /// Whether the quote with timestamp `ts` is expired.
42    pub fn is_expired(&self, now: i64, ts: i64) -> bool {
43        if self.disabled {
44            return true;
45        }
46
47        now.checked_sub(ts)
48            .map(|d| d > 60 * 60 * 24 * (self.tcb_validity_period as i64))
49            .expect("quote timestamp is in the future") // This should never happen.
50    }
51}
52
53/// TDX-specific quote policy.
54#[derive(Clone, Debug, Default, PartialEq, Eq, cbor::Encode, cbor::Decode)]
55pub struct TdxQuotePolicy {
56    /// Allowed TDX modules. Empty to allow ANY Intel-signed module.
57    pub allowed_tdx_modules: Vec<TdxModulePolicy>,
58}
59
60impl TdxQuotePolicy {
61    /// Verify whether the TDX policy is satisfied for the given report.
62    pub fn verify(&self, report: &TdReport) -> Result<(), Error> {
63        self.verify_tdx_module(report)?;
64        Ok(())
65    }
66
67    fn verify_tdx_module(&self, report: &TdReport) -> Result<(), Error> {
68        // If at least one TDX Module matches, then we are good.
69        for allowed_module in &self.allowed_tdx_modules {
70            if allowed_module.matches(report) {
71                return Ok(());
72            }
73        }
74
75        // No module matched. Iff the list of modules is empty, allow ANY Intel-signed module.
76        // As per the TDX specifications, MRSIGNER is all-zero for Intel.
77        if self.allowed_tdx_modules.is_empty() && report.mr_signer_seam == TDX_MRSIGNER_INTEL {
78            return Ok(());
79        }
80
81        Err(Error::TdxModuleNotAllowed)
82    }
83}
84
85/// TDX module policy.
86#[derive(Clone, Debug, PartialEq, Eq, cbor::Encode, cbor::Decode)]
87#[cbor(no_default)]
88pub struct TdxModulePolicy {
89    /// Optional allowed measurement of the TDX Module. In case it is `None`, ANY measurement is
90    /// allowed and only the signer is checked.
91    pub mr_seam: Option<[u8; 48]>,
92
93    /// Allowed signer of the TDX Module (zero for Intel).
94    pub mr_signer_seam: [u8; 48],
95}
96
97impl TdxModulePolicy {
98    /// Returns true iff the TDX module in the given report matches this module policy.
99    pub fn matches(&self, report: &TdReport) -> bool {
100        // Check MRSEAM if set.
101        if let Some(mr_seam) = self.mr_seam {
102            if mr_seam != report.mr_seam {
103                return false;
104            }
105        }
106
107        // Check MRSIGNER.
108        if self.mr_signer_seam != report.mr_signer_seam {
109            return false;
110        }
111
112        true
113    }
114}